From e56dc9e2949edff7932474f2552dd134734cc857 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 30 Jul 2020 20:33:57 -0400 Subject: nfsd: remove fault injection code It was an interesting idea but nobody seems to be using it, it's buggy at this point, and nfs4state.c is already complicated enough without it. The new nfsd/clients/ code provides some of the same functionality, and could probably do more if desired. This feature has been deprecated since 9d60d93198c6 ("Deprecate nfsd fault injection"). Signed-off-by: J. Bruce Fields --- fs/nfsd/Kconfig | 10 - fs/nfsd/Makefile | 1 - fs/nfsd/nfs4state.c | 593 ---------------------------------------------------- fs/nfsd/nfsctl.c | 3 - fs/nfsd/state.h | 27 --- 5 files changed, 634 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index 99d2cae91bd6..9223e13c3051 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig @@ -156,13 +156,3 @@ config NFSD_V4_SECURITY_LABEL If you do not wish to enable fine-grained security labels SELinux or Smack policies on NFSv4 files, say N. - -config NFSD_FAULT_INJECTION - bool "NFS server manual fault injection" - depends on NFSD_V4 && DEBUG_KERNEL && DEBUG_FS && BROKEN - help - This option enables support for manually injecting faults - into the NFS server. This is intended to be used for - testing error recovery on the NFS client. - - If unsure, say N. diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile index 6a40b1afe703..3f0983e93a99 100644 --- a/fs/nfsd/Makefile +++ b/fs/nfsd/Makefile @@ -13,7 +13,6 @@ nfsd-y += trace.o nfsd-y += nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \ export.o auth.o lockd.o nfscache.o nfsxdr.o \ stats.o filecache.o -nfsd-$(CONFIG_NFSD_FAULT_INJECTION) += fault_inject.o nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index c09a2a4281ec..a31ba0e4ef2f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -7253,599 +7253,6 @@ nfs4_check_open_reclaim(clientid_t *clid, return nfs_ok; } -#ifdef CONFIG_NFSD_FAULT_INJECTION -static inline void -put_client(struct nfs4_client *clp) -{ - atomic_dec(&clp->cl_rpc_users); -} - -static struct nfs4_client * -nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size) -{ - struct nfs4_client *clp; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - - if (!nfsd_netns_ready(nn)) - return NULL; - - list_for_each_entry(clp, &nn->client_lru, cl_lru) { - if (memcmp(&clp->cl_addr, addr, addr_size) == 0) - return clp; - } - return NULL; -} - -u64 -nfsd_inject_print_clients(void) -{ - struct nfs4_client *clp; - u64 count = 0; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - char buf[INET6_ADDRSTRLEN]; - - if (!nfsd_netns_ready(nn)) - return 0; - - spin_lock(&nn->client_lock); - list_for_each_entry(clp, &nn->client_lru, cl_lru) { - rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); - pr_info("NFS Client: %s\n", buf); - ++count; - } - spin_unlock(&nn->client_lock); - - return count; -} - -u64 -nfsd_inject_forget_client(struct sockaddr_storage *addr, size_t addr_size) -{ - u64 count = 0; - struct nfs4_client *clp; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - - if (!nfsd_netns_ready(nn)) - return count; - - spin_lock(&nn->client_lock); - clp = nfsd_find_client(addr, addr_size); - if (clp) { - if (mark_client_expired_locked(clp) == nfs_ok) - ++count; - else - clp = NULL; - } - spin_unlock(&nn->client_lock); - - if (clp) - expire_client(clp); - - return count; -} - -u64 -nfsd_inject_forget_clients(u64 max) -{ - u64 count = 0; - struct nfs4_client *clp, *next; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - LIST_HEAD(reaplist); - - if (!nfsd_netns_ready(nn)) - return count; - - spin_lock(&nn->client_lock); - list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { - if (mark_client_expired_locked(clp) == nfs_ok) { - list_add(&clp->cl_lru, &reaplist); - if (max != 0 && ++count >= max) - break; - } - } - spin_unlock(&nn->client_lock); - - list_for_each_entry_safe(clp, next, &reaplist, cl_lru) - expire_client(clp); - - return count; -} - -static void nfsd_print_count(struct nfs4_client *clp, unsigned int count, - const char *type) -{ - char buf[INET6_ADDRSTRLEN]; - rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf)); - printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type); -} - -static void -nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst, - struct list_head *collect) -{ - struct nfs4_client *clp = lst->st_stid.sc_client; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - - if (!collect) - return; - - lockdep_assert_held(&nn->client_lock); - atomic_inc(&clp->cl_rpc_users); - list_add(&lst->st_locks, collect); -} - -static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, - struct list_head *collect, - bool (*func)(struct nfs4_ol_stateid *)) -{ - struct nfs4_openowner *oop; - struct nfs4_ol_stateid *stp, *st_next; - struct nfs4_ol_stateid *lst, *lst_next; - u64 count = 0; - - spin_lock(&clp->cl_lock); - list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) { - list_for_each_entry_safe(stp, st_next, - &oop->oo_owner.so_stateids, st_perstateowner) { - list_for_each_entry_safe(lst, lst_next, - &stp->st_locks, st_locks) { - if (func) { - if (func(lst)) - nfsd_inject_add_lock_to_list(lst, - collect); - } - ++count; - /* - * Despite the fact that these functions deal - * with 64-bit integers for "count", we must - * ensure that it doesn't blow up the - * clp->cl_rpc_users. Throw a warning if we - * start to approach INT_MAX here. - */ - WARN_ON_ONCE(count == (INT_MAX / 2)); - if (count == max) - goto out; - } - } - } -out: - spin_unlock(&clp->cl_lock); - - return count; -} - -static u64 -nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect, - u64 max) -{ - return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid); -} - -static u64 -nfsd_print_client_locks(struct nfs4_client *clp) -{ - u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL); - nfsd_print_count(clp, count, "locked files"); - return count; -} - -u64 -nfsd_inject_print_locks(void) -{ - struct nfs4_client *clp; - u64 count = 0; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - - if (!nfsd_netns_ready(nn)) - return 0; - - spin_lock(&nn->client_lock); - list_for_each_entry(clp, &nn->client_lru, cl_lru) - count += nfsd_print_client_locks(clp); - spin_unlock(&nn->client_lock); - - return count; -} - -static void -nfsd_reap_locks(struct list_head *reaplist) -{ - struct nfs4_client *clp; - struct nfs4_ol_stateid *stp, *next; - - list_for_each_entry_safe(stp, next, reaplist, st_locks) { - list_del_init(&stp->st_locks); - clp = stp->st_stid.sc_client; - nfs4_put_stid(&stp->st_stid); - put_client(clp); - } -} - -u64 -nfsd_inject_forget_client_locks(struct sockaddr_storage *addr, size_t addr_size) -{ - unsigned int count = 0; - struct nfs4_client *clp; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - LIST_HEAD(reaplist); - - if (!nfsd_netns_ready(nn)) - return count; - - spin_lock(&nn->client_lock); - clp = nfsd_find_client(addr, addr_size); - if (clp) - count = nfsd_collect_client_locks(clp, &reaplist, 0); - spin_unlock(&nn->client_lock); - nfsd_reap_locks(&reaplist); - return count; -} - -u64 -nfsd_inject_forget_locks(u64 max) -{ - u64 count = 0; - struct nfs4_client *clp; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - LIST_HEAD(reaplist); - - if (!nfsd_netns_ready(nn)) - return count; - - spin_lock(&nn->client_lock); - list_for_each_entry(clp, &nn->client_lru, cl_lru) { - count += nfsd_collect_client_locks(clp, &reaplist, max - count); - if (max != 0 && count >= max) - break; - } - spin_unlock(&nn->client_lock); - nfsd_reap_locks(&reaplist); - return count; -} - -static u64 -nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max, - struct list_head *collect, - void (*func)(struct nfs4_openowner *)) -{ - struct nfs4_openowner *oop, *next; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - u64 count = 0; - - lockdep_assert_held(&nn->client_lock); - - spin_lock(&clp->cl_lock); - list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) { - if (func) { - func(oop); - if (collect) { - atomic_inc(&clp->cl_rpc_users); - list_add(&oop->oo_perclient, collect); - } - } - ++count; - /* - * Despite the fact that these functions deal with - * 64-bit integers for "count", we must ensure that - * it doesn't blow up the clp->cl_rpc_users. Throw a - * warning if we start to approach INT_MAX here. - */ - WARN_ON_ONCE(count == (INT_MAX / 2)); - if (count == max) - break; - } - spin_unlock(&clp->cl_lock); - - return count; -} - -static u64 -nfsd_print_client_openowners(struct nfs4_client *clp) -{ - u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL); - - nfsd_print_count(clp, count, "openowners"); - return count; -} - -static u64 -nfsd_collect_client_openowners(struct nfs4_client *clp, - struct list_head *collect, u64 max) -{ - return nfsd_foreach_client_openowner(clp, max, collect, - unhash_openowner_locked); -} - -u64 -nfsd_inject_print_openowners(void) -{ - struct nfs4_client *clp; - u64 count = 0; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - - if (!nfsd_netns_ready(nn)) - return 0; - - spin_lock(&nn->client_lock); - list_for_each_entry(clp, &nn->client_lru, cl_lru) - count += nfsd_print_client_openowners(clp); - spin_unlock(&nn->client_lock); - - return count; -} - -static void -nfsd_reap_openowners(struct list_head *reaplist) -{ - struct nfs4_client *clp; - struct nfs4_openowner *oop, *next; - - list_for_each_entry_safe(oop, next, reaplist, oo_perclient) { - list_del_init(&oop->oo_perclient); - clp = oop->oo_owner.so_client; - release_openowner(oop); - put_client(clp); - } -} - -u64 -nfsd_inject_forget_client_openowners(struct sockaddr_storage *addr, - size_t addr_size) -{ - unsigned int count = 0; - struct nfs4_client *clp; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - LIST_HEAD(reaplist); - - if (!nfsd_netns_ready(nn)) - return count; - - spin_lock(&nn->client_lock); - clp = nfsd_find_client(addr, addr_size); - if (clp) - count = nfsd_collect_client_openowners(clp, &reaplist, 0); - spin_unlock(&nn->client_lock); - nfsd_reap_openowners(&reaplist); - return count; -} - -u64 -nfsd_inject_forget_openowners(u64 max) -{ - u64 count = 0; - struct nfs4_client *clp; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - LIST_HEAD(reaplist); - - if (!nfsd_netns_ready(nn)) - return count; - - spin_lock(&nn->client_lock); - list_for_each_entry(clp, &nn->client_lru, cl_lru) { - count += nfsd_collect_client_openowners(clp, &reaplist, - max - count); - if (max != 0 && count >= max) - break; - } - spin_unlock(&nn->client_lock); - nfsd_reap_openowners(&reaplist); - return count; -} - -static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, - struct list_head *victims) -{ - struct nfs4_delegation *dp, *next; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - u64 count = 0; - - lockdep_assert_held(&nn->client_lock); - - spin_lock(&state_lock); - list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) { - if (victims) { - /* - * It's not safe to mess with delegations that have a - * non-zero dl_time. They might have already been broken - * and could be processed by the laundromat outside of - * the state_lock. Just leave them be. - */ - if (dp->dl_time != 0) - continue; - - atomic_inc(&clp->cl_rpc_users); - WARN_ON(!unhash_delegation_locked(dp)); - list_add(&dp->dl_recall_lru, victims); - } - ++count; - /* - * Despite the fact that these functions deal with - * 64-bit integers for "count", we must ensure that - * it doesn't blow up the clp->cl_rpc_users. Throw a - * warning if we start to approach INT_MAX here. - */ - WARN_ON_ONCE(count == (INT_MAX / 2)); - if (count == max) - break; - } - spin_unlock(&state_lock); - return count; -} - -static u64 -nfsd_print_client_delegations(struct nfs4_client *clp) -{ - u64 count = nfsd_find_all_delegations(clp, 0, NULL); - - nfsd_print_count(clp, count, "delegations"); - return count; -} - -u64 -nfsd_inject_print_delegations(void) -{ - struct nfs4_client *clp; - u64 count = 0; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - - if (!nfsd_netns_ready(nn)) - return 0; - - spin_lock(&nn->client_lock); - list_for_each_entry(clp, &nn->client_lru, cl_lru) - count += nfsd_print_client_delegations(clp); - spin_unlock(&nn->client_lock); - - return count; -} - -static void -nfsd_forget_delegations(struct list_head *reaplist) -{ - struct nfs4_client *clp; - struct nfs4_delegation *dp, *next; - - list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { - list_del_init(&dp->dl_recall_lru); - clp = dp->dl_stid.sc_client; - revoke_delegation(dp); - put_client(clp); - } -} - -u64 -nfsd_inject_forget_client_delegations(struct sockaddr_storage *addr, - size_t addr_size) -{ - u64 count = 0; - struct nfs4_client *clp; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - LIST_HEAD(reaplist); - - if (!nfsd_netns_ready(nn)) - return count; - - spin_lock(&nn->client_lock); - clp = nfsd_find_client(addr, addr_size); - if (clp) - count = nfsd_find_all_delegations(clp, 0, &reaplist); - spin_unlock(&nn->client_lock); - - nfsd_forget_delegations(&reaplist); - return count; -} - -u64 -nfsd_inject_forget_delegations(u64 max) -{ - u64 count = 0; - struct nfs4_client *clp; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - LIST_HEAD(reaplist); - - if (!nfsd_netns_ready(nn)) - return count; - - spin_lock(&nn->client_lock); - list_for_each_entry(clp, &nn->client_lru, cl_lru) { - count += nfsd_find_all_delegations(clp, max - count, &reaplist); - if (max != 0 && count >= max) - break; - } - spin_unlock(&nn->client_lock); - nfsd_forget_delegations(&reaplist); - return count; -} - -static void -nfsd_recall_delegations(struct list_head *reaplist) -{ - struct nfs4_client *clp; - struct nfs4_delegation *dp, *next; - - list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) { - list_del_init(&dp->dl_recall_lru); - clp = dp->dl_stid.sc_client; - - trace_nfsd_deleg_recall(&dp->dl_stid.sc_stateid); - - /* - * We skipped all entries that had a zero dl_time before, - * so we can now reset the dl_time back to 0. If a delegation - * break comes in now, then it won't make any difference since - * we're recalling it either way. - */ - spin_lock(&state_lock); - dp->dl_time = 0; - spin_unlock(&state_lock); - nfsd_break_one_deleg(dp); - put_client(clp); - } -} - -u64 -nfsd_inject_recall_client_delegations(struct sockaddr_storage *addr, - size_t addr_size) -{ - u64 count = 0; - struct nfs4_client *clp; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - LIST_HEAD(reaplist); - - if (!nfsd_netns_ready(nn)) - return count; - - spin_lock(&nn->client_lock); - clp = nfsd_find_client(addr, addr_size); - if (clp) - count = nfsd_find_all_delegations(clp, 0, &reaplist); - spin_unlock(&nn->client_lock); - - nfsd_recall_delegations(&reaplist); - return count; -} - -u64 -nfsd_inject_recall_delegations(u64 max) -{ - u64 count = 0; - struct nfs4_client *clp, *next; - struct nfsd_net *nn = net_generic(current->nsproxy->net_ns, - nfsd_net_id); - LIST_HEAD(reaplist); - - if (!nfsd_netns_ready(nn)) - return count; - - spin_lock(&nn->client_lock); - list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) { - count += nfsd_find_all_delegations(clp, max - count, &reaplist); - if (max != 0 && ++count >= max) - break; - } - spin_unlock(&nn->client_lock); - nfsd_recall_delegations(&reaplist); - return count; -} -#endif /* CONFIG_NFSD_FAULT_INJECTION */ - /* * Since the lifetime of a delegation isn't limited to that of an open, a * client may quite reasonably hang on to a delegation as long as it has diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index 7ae236113040..f6d5d783f4a4 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -1534,7 +1534,6 @@ static int __init init_nfsd(void) retval = nfsd4_init_pnfs(); if (retval) goto out_free_slabs; - nfsd_fault_inject_init(); /* nfsd fault injection controls */ nfsd_stat_init(); /* Statistics */ retval = nfsd_drc_slab_create(); if (retval) @@ -1555,7 +1554,6 @@ out_free_lockd: nfsd_drc_slab_free(); out_free_stat: nfsd_stat_shutdown(); - nfsd_fault_inject_cleanup(); nfsd4_exit_pnfs(); out_free_slabs: nfsd4_free_slabs(); @@ -1575,7 +1573,6 @@ static void __exit exit_nfsd(void) nfsd_lockd_shutdown(); nfsd4_free_slabs(); nfsd4_exit_pnfs(); - nfsd_fault_inject_cleanup(); unregister_filesystem(&nfsd_fs_type); unregister_cld_notifier(); unregister_pernet_subsys(&nfsd_net_ops); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 3b408532a5dc..9eae11a9d21c 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -693,31 +693,4 @@ extern void nfsd4_client_record_remove(struct nfs4_client *clp); extern int nfsd4_client_record_check(struct nfs4_client *clp); extern void nfsd4_record_grace_done(struct nfsd_net *nn); -/* nfs fault injection functions */ -#ifdef CONFIG_NFSD_FAULT_INJECTION -void nfsd_fault_inject_init(void); -void nfsd_fault_inject_cleanup(void); - -u64 nfsd_inject_print_clients(void); -u64 nfsd_inject_forget_client(struct sockaddr_storage *, size_t); -u64 nfsd_inject_forget_clients(u64); - -u64 nfsd_inject_print_locks(void); -u64 nfsd_inject_forget_client_locks(struct sockaddr_storage *, size_t); -u64 nfsd_inject_forget_locks(u64); - -u64 nfsd_inject_print_openowners(void); -u64 nfsd_inject_forget_client_openowners(struct sockaddr_storage *, size_t); -u64 nfsd_inject_forget_openowners(u64); - -u64 nfsd_inject_print_delegations(void); -u64 nfsd_inject_forget_client_delegations(struct sockaddr_storage *, size_t); -u64 nfsd_inject_forget_delegations(u64); -u64 nfsd_inject_recall_client_delegations(struct sockaddr_storage *, size_t); -u64 nfsd_inject_recall_delegations(u64); -#else /* CONFIG_NFSD_FAULT_INJECTION */ -static inline void nfsd_fault_inject_init(void) {} -static inline void nfsd_fault_inject_cleanup(void) {} -#endif /* CONFIG_NFSD_FAULT_INJECTION */ - #endif /* NFSD4_STATE_H */ -- cgit From 12ed22f3c3dc75687ec532534aa01cd41111c1f8 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 31 Jul 2020 16:20:05 -0400 Subject: nfsd: give up callbacks on revoked delegations The delegation is no longer returnable, so I don't think there's much point retrying the recall. (I think it's worth asking why we even need separate CLOSED_DELEG and REVOKED_DELEG states. But treating them the same would currently cause nfsd4_free_stateid to call list_del_init(&dp->dl_recall_lru) on a delegation that the laundromat had unhashed but not revoked, incorrectly removing it from the laundromat's reaplist or a client's dl_recall_lru.) Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index a31ba0e4ef2f..e8b41c5e5147 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4513,7 +4513,8 @@ static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, { struct nfs4_delegation *dp = cb_to_delegation(cb); - if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID) + if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID || + dp->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID) return 1; switch (task->tk_status) { -- cgit From 4cce11fa48b8e9634309e5eac5aa49046e6a72c1 Mon Sep 17 00:00:00 2001 From: Alex Dewar Date: Mon, 17 Aug 2020 18:51:26 +0100 Subject: nfsd: Fix typo in comment Missing "is". Signed-off-by: Alex Dewar Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 259d5ad0e3f4..61ebc28cad9e 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4828,7 +4828,7 @@ nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr, slen = strlen(sp); /* - * Check if this a user. attribute, skip it if not. + * Check if this is a "user." attribute, skip it if not. */ if (strncmp(sp, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) goto contloop; -- cgit From e2a1840e56a1ace8bce86bc7e40923b4b2748404 Mon Sep 17 00:00:00 2001 From: Alex Dewar Date: Wed, 12 Aug 2020 15:12:51 +0100 Subject: nfsd: Remove unnecessary assignment in nfs4xdr.c In nfsd4_encode_listxattrs(), the variable p is assigned to at one point but this value is never used before p is reassigned. Fix this. Addresses-Coverity: ("Unused value") Signed-off-by: Alex Dewar Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 61ebc28cad9e..3d263fd20df0 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4859,7 +4859,7 @@ nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr, goto out; } - p = xdr_encode_opaque(p, sp, slen); + xdr_encode_opaque(p, sp, slen); xdrleft -= xdrlen; count++; -- cgit From 3caf91757ced158e6c4a44d8b105bd7b3e1767d8 Mon Sep 17 00:00:00 2001 From: Hou Tao Date: Fri, 28 Aug 2020 15:02:55 +0800 Subject: nfsd: rename delegation related tracepoints to make them less confusing Now when a read delegation is given, two delegation related traces will be printed: nfsd_deleg_open: client 5f45b854:e6058001 stateid 00000030:00000001 nfsd_deleg_none: client 5f45b854:e6058001 stateid 0000002f:00000001 Although the intention is to let developers know two stateid are returned, the traces are confusing about whether or not a read delegation is handled out. So renaming trace_nfsd_deleg_none() to trace_nfsd_open() and trace_nfsd_deleg_open() to trace_nfsd_deleg_read() to make the intension clearer. The patched traces will be: nfsd_deleg_read: client 5f48a967:b55b21cd stateid 00000003:00000001 nfsd_open: client 5f48a967:b55b21cd stateid 00000002:00000001 Suggested-by: Chuck Lever Signed-off-by: Hou Tao Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 4 ++-- fs/nfsd/trace.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e8b41c5e5147..726046b6b370 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -5127,7 +5127,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid)); - trace_nfsd_deleg_open(&dp->dl_stid.sc_stateid); + trace_nfsd_deleg_read(&dp->dl_stid.sc_stateid); open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; nfs4_put_stid(&dp->dl_stid); return; @@ -5244,7 +5244,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf nfs4_open_delegation(current_fh, open, stp); nodeleg: status = nfs_ok; - trace_nfsd_deleg_none(&stp->st_stid.sc_stateid); + trace_nfsd_open(&stp->st_stid.sc_stateid); out: /* 4.1 client trying to upgrade/downgrade delegation? */ if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp && diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h index 1861db1bdc67..99bf07800cd0 100644 --- a/fs/nfsd/trace.h +++ b/fs/nfsd/trace.h @@ -289,8 +289,8 @@ DEFINE_STATEID_EVENT(layout_recall_done); DEFINE_STATEID_EVENT(layout_recall_fail); DEFINE_STATEID_EVENT(layout_recall_release); -DEFINE_STATEID_EVENT(deleg_open); -DEFINE_STATEID_EVENT(deleg_none); +DEFINE_STATEID_EVENT(open); +DEFINE_STATEID_EVENT(deleg_read); DEFINE_STATEID_EVENT(deleg_break); DEFINE_STATEID_EVENT(deleg_recall); -- cgit From 403217f30418c808600e3e8e345413ba5cc15676 Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Mon, 17 Aug 2020 12:53:06 -0400 Subject: SUNRPC/NFSD: Implement xdr_reserve_space_vec() Reserving space for a large READ payload requires special handling when reserving space in the xdr buffer pages. One problem we can have is use of the scratch buffer, which is used to get a pointer to a contiguous region of data up to PAGE_SIZE. When using the scratch buffer, calls to xdr_commit_encode() shift the data to it's proper alignment in the xdr buffer. If we've reserved several pages in a vector, then this could potentially invalidate earlier pointers and result in incorrect READ data being sent to the client. I get around this by looking at the amount of space left in the current page, and never reserve more than that for each entry in the read vector. This lets us place data directly where it needs to go in the buffer pages. Signed-off-by: Anna Schumaker Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 3d263fd20df0..36a54827085b 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -3814,36 +3814,14 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp, { struct xdr_stream *xdr = &resp->xdr; u32 eof; - int v; int starting_len = xdr->buf->len - 8; - long len; - int thislen; __be32 nfserr; __be32 tmp; - __be32 *p; int pad; - /* - * svcrdma requires every READ payload to start somewhere - * in xdr->pages. - */ - if (xdr->iov == xdr->buf->head) { - xdr->iov = NULL; - xdr->end = xdr->p; - } - - len = maxcount; - v = 0; - while (len) { - thislen = min_t(long, len, PAGE_SIZE); - p = xdr_reserve_space(xdr, thislen); - WARN_ON_ONCE(!p); - resp->rqstp->rq_vec[v].iov_base = p; - resp->rqstp->rq_vec[v].iov_len = thislen; - v++; - len -= thislen; - } - read->rd_vlen = v; + read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, maxcount); + if (read->rd_vlen < 0) + return nfserr_resource; nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen, &maxcount, -- cgit From 8237284a00d99546c1c98d8f621cf5bd475b49fd Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 11 Sep 2020 14:47:48 -0400 Subject: NFSD: Correct type annotations in user xattr helpers Squelch some sparse warnings: /home/cel/src/linux/linux/fs/nfsd/vfs.c:2264:13: warning: incorrect type in assignment (different base types) /home/cel/src/linux/linux/fs/nfsd/vfs.c:2264:13: expected int err /home/cel/src/linux/linux/fs/nfsd/vfs.c:2264:13: got restricted __be32 /home/cel/src/linux/linux/fs/nfsd/vfs.c:2266:24: warning: incorrect type in return expression (different base types) /home/cel/src/linux/linux/fs/nfsd/vfs.c:2266:24: expected restricted __be32 /home/cel/src/linux/linux/fs/nfsd/vfs.c:2266:24: got int err /home/cel/src/linux/linux/fs/nfsd/vfs.c:2288:13: warning: incorrect type in assignment (different base types) /home/cel/src/linux/linux/fs/nfsd/vfs.c:2288:13: expected int err /home/cel/src/linux/linux/fs/nfsd/vfs.c:2288:13: got restricted __be32 /home/cel/src/linux/linux/fs/nfsd/vfs.c:2290:24: warning: incorrect type in return expression (different base types) /home/cel/src/linux/linux/fs/nfsd/vfs.c:2290:24: expected restricted __be32 /home/cel/src/linux/linux/fs/nfsd/vfs.c:2290:24: got int err Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/vfs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index aba5af9df328..1ecaceebee13 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -2259,7 +2259,8 @@ out: __be32 nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name) { - int err, ret; + __be32 err; + int ret; err = fh_verify(rqstp, fhp, 0, NFSD_MAY_WRITE); if (err) @@ -2283,7 +2284,8 @@ __be32 nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name, void *buf, u32 len, u32 flags) { - int err, ret; + __be32 err; + int ret; err = fh_verify(rqstp, fhp, 0, NFSD_MAY_WRITE); if (err) -- cgit From b9a492376d51facace13c1b9eb06d64925962878 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 11 Sep 2020 14:47:53 -0400 Subject: NFSD: Correct type annotations in user xattr XDR functions Squelch some sparse warnings: /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:4692:24: warning: incorrect type in return expression (different base types) /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:4692:24: expected int /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:4692:24: got restricted __be32 [usertype] /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:4702:32: warning: incorrect type in return expression (different base types) /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:4702:32: expected int /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:4702:32: got restricted __be32 [usertype] /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:4739:13: warning: incorrect type in assignment (different base types) /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:4739:13: expected restricted __be32 [usertype] err /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:4739:13: got int /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:4891:15: warning: incorrect type in assignment (different base types) /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:4891:15: expected unsigned int [assigned] [usertype] count /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:4891:15: got restricted __be32 [usertype] Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 36a54827085b..205d23a41717 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4657,7 +4657,7 @@ nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p) /* * Encode kmalloc-ed buffer in to XDR stream. */ -static int +static __be32 nfsd4_vbuf_to_stream(struct xdr_stream *xdr, char *buf, u32 buflen) { u32 cplen; @@ -4773,7 +4773,7 @@ nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr, u32 xdrlen, offset; u64 cookie; char *sp; - __be32 status; + __be32 status, tmp; __be32 *p; u32 nuser; @@ -4866,8 +4866,8 @@ wreof: cookie = offset + count; write_bytes_to_xdr_buf(xdr->buf, cookie_offset, &cookie, 8); - count = htonl(count); - write_bytes_to_xdr_buf(xdr->buf, count_offset, &count, 4); + tmp = cpu_to_be32(count); + write_bytes_to_xdr_buf(xdr->buf, count_offset, &tmp, 4); out: if (listxattrs->lsxa_len) kvfree(listxattrs->lsxa_buf); -- cgit From 5aff7d0820c472f52153ec5f9abf1df4dea28f3d Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 11 Sep 2020 14:47:59 -0400 Subject: NFSD: Correct type annotations in COPY XDR functions Squelch some sparse warnings: /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:1860:16: warning: incorrect type in assignment (different base types) /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:1860:16: expected int status /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:1860:16: got restricted __be32 /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:1862:24: warning: incorrect type in return expression (different base types) /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:1862:24: expected restricted __be32 /home/cel/src/linux/linux/fs/nfsd/nfs4xdr.c:1862:24: got int status Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 205d23a41717..c11943a0c1db 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1855,7 +1855,7 @@ static __be32 nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp, struct nfsd4_copy_notify *cn) { - int status; + __be32 status; status = nfsd4_decode_stateid(argp, &cn->cpn_src_stateid); if (status) -- cgit From 44b49aa65f8603ad274c448310b5ff95a78d394c Mon Sep 17 00:00:00 2001 From: Zheng Bin Date: Fri, 11 Sep 2020 12:10:14 +0800 Subject: nfsd: fix comparison to bool warning Fixes coccicheck warning: fs/nfsd/nfs4proc.c:3234:5-29: WARNING: Comparison to bool Signed-off-by: Zheng Bin Signed-off-by: J. Bruce Fields --- 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 eaf50eafa935..63e5a4844d8c 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -3231,7 +3231,7 @@ bool nfsd4_spo_must_allow(struct svc_rqst *rqstp) if (!cstate->minorversion) return false; - if (cstate->spo_must_allowed == true) + if (cstate->spo_must_allowed) return true; opiter = resp->opcnt; -- cgit From 8c38b705b4f4ca4e7f9cc116141bc38391917c30 Mon Sep 17 00:00:00 2001 From: Rik van Riel Date: Mon, 14 Sep 2020 13:07:19 -0400 Subject: silence nfscache allocation warnings with kvzalloc silence nfscache allocation warnings with kvzalloc Currently nfsd_reply_cache_init attempts hash table allocation through kmalloc, and manually falls back to vzalloc if that fails. This makes the code a little larger than needed, and creates a significant amount of serial console spam if you have enough systems. Switching to kvzalloc gets rid of the allocation warnings, and makes the code a little cleaner too as a side effect. Freeing of nn->drc_hashtbl is already done using kvfree currently. Signed-off-by: Rik van Riel Signed-off-by: J. Bruce Fields --- fs/nfsd/nfscache.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index 0a0cf1fd77d3..80c90fc231a5 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -172,14 +172,10 @@ int nfsd_reply_cache_init(struct nfsd_net *nn) if (status) goto out_nomem; - nn->drc_hashtbl = kcalloc(hashsize, - sizeof(*nn->drc_hashtbl), GFP_KERNEL); - if (!nn->drc_hashtbl) { - nn->drc_hashtbl = vzalloc(array_size(hashsize, - sizeof(*nn->drc_hashtbl))); - if (!nn->drc_hashtbl) - goto out_shrinker; - } + nn->drc_hashtbl = kvzalloc(array_size(hashsize, + sizeof(*nn->drc_hashtbl)), GFP_KERNEL); + if (!nn->drc_hashtbl) + goto out_shrinker; for (i = 0; i < hashsize; i++) { INIT_LIST_HEAD(&nn->drc_hashtbl[i].lru_head); -- cgit From ae3c57b5ca47665dc3416447a5534a9796096d86 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 17 Jul 2020 18:54:54 -0400 Subject: nfsd: Cache R, RW, and W opens separately The nfsd open code has always kept separate read-only, read-write, and write-only opens as necessary to ensure that when a client closes or downgrades, we don't retain more access than necessary. Also, I didn't realize the cache behaved this way when I wrote 94415b06eb8a "nfsd4: a client's own opens needn't prevent delegations". There I assumed fi_fds[O_WRONLY] and fi_fds[O_RDWR] would always be distinct. The violation of that assumption is triggering a WARN_ON_ONCE() and could also cause the server to give out a delegation when it shouldn't. Fixes: 94415b06eb8a ("nfsd4: a client's own opens needn't prevent delegations") Tested-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/filecache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c index c8b9d2667ee6..3c6c2f7d1688 100644 --- a/fs/nfsd/filecache.c +++ b/fs/nfsd/filecache.c @@ -889,7 +889,7 @@ nfsd_file_find_locked(struct inode *inode, unsigned int may_flags, hlist_for_each_entry_rcu(nf, &nfsd_file_hashtbl[hashval].nfb_head, nf_node, lockdep_is_held(&nfsd_file_hashtbl[hashval].nfb_lock)) { - if ((need & nf->nf_may) != need) + if (nf->nf_may != need) continue; if (nf->nf_inode != inode) continue; -- cgit From 50747dd5e47bde3b7d7f839c84d0d3b554090497 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 25 Sep 2020 10:09:58 -0400 Subject: nfsd4: remove check_conflicting_opens warning There are actually rare races where this is possible (e.g. if a new open intervenes between the read of i_writecount and the fi_fds). Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 1 - 1 file changed, 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 726046b6b370..a59551efd263 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4955,7 +4955,6 @@ static int nfsd4_check_conflicting_opens(struct nfs4_client *clp, writes--; if (fp->fi_fds[O_RDWR]) writes--; - WARN_ON_ONCE(writes < 0); if (writes > 0) return -EAGAIN; spin_lock(&fp->fi_lock); -- cgit From 13956160fc7c75706178cb05c0ac9f5ca77c6411 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 25 Sep 2020 10:12:39 -0400 Subject: nfsd: rq_lease_breaker cleanup Since only the v4 code cares about it, maybe it's better to leave rq_lease_breaker out of the common dispatch code? Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 3 ++- fs/nfsd/nfssvc.c | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index a59551efd263..4f3964582b68 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4598,7 +4598,8 @@ static bool nfsd_breaker_owns_lease(struct file_lock *fl) if (!i_am_nfsd()) return NULL; rqst = kthread_data(current); - if (!rqst->rq_lease_breaker) + /* Note rq_prog == NFS_ACL_PROGRAM is also possible: */ + if (rqst->rq_prog != NFS_PROGRAM || rqst->rq_vers < 4) return NULL; clp = *(rqst->rq_lease_breaker); return dl->dl_stid.sc_client == clp; diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index f7f6473578af..f6bc94cab9da 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -1016,7 +1016,6 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) *statp = rpc_garbage_args; return 1; } - rqstp->rq_lease_breaker = NULL; /* * Give the xdr decoder a chance to change this if it wants * (necessary in the NFSv4.0 compound case) -- cgit From 6b3dccd48de8a4c650b01499a0b09d1e2279649e Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 1 Oct 2020 18:58:56 -0400 Subject: NFSD: Add missing NFSv2 .pc_func methods There's no protection in nfsd_dispatch() against a NULL .pc_func helpers. A malicious NFS client can trigger a crash by invoking the unused/unsupported NFSv2 ROOT or WRITECACHE procedures. The current NFSD dispatcher does not support returning a void reply to a non-NULL procedure, so the reply to both of these is wrong, for the moment. Cc: Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfsproc.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'fs') diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 6e0b066480c5..6d1b3af40a4f 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -118,6 +118,13 @@ done: return nfsd_return_attrs(nfserr, resp); } +/* Obsolete, replaced by MNTPROC_MNT. */ +static __be32 +nfsd_proc_root(struct svc_rqst *rqstp) +{ + return nfs_ok; +} + /* * Look up a path name component * Note: the dentry in the resp->fh may be negative if the file @@ -203,6 +210,13 @@ nfsd_proc_read(struct svc_rqst *rqstp) return fh_getattr(&resp->fh, &resp->stat); } +/* Reserved */ +static __be32 +nfsd_proc_writecache(struct svc_rqst *rqstp) +{ + return nfs_ok; +} + /* * Write data to a file * N.B. After this call resp->fh needs an fh_put @@ -617,6 +631,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { .pc_xdrressize = ST+AT, }, [NFSPROC_ROOT] = { + .pc_func = nfsd_proc_root, .pc_decode = nfssvc_decode_void, .pc_encode = nfssvc_encode_void, .pc_argsize = sizeof(struct nfsd_void), @@ -654,6 +669,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { .pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4, }, [NFSPROC_WRITECACHE] = { + .pc_func = nfsd_proc_writecache, .pc_decode = nfssvc_decode_void, .pc_encode = nfssvc_encode_void, .pc_argsize = sizeof(struct nfsd_void), -- cgit From 49d99608213b60dec319400edf997e0fe0567cdf Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 1 Oct 2020 18:59:02 -0400 Subject: lockd: Replace PROC() macro with open code Clean up: Follow-up on ten-year-old commit b9081d90f5b9 ("NFS: kill off complicated macro 'PROC'") by performing the same conversion in the lockd code. To reduce the chance of error, I copied the original C preprocessor output and then made some minor edits. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/lockd/svc4proc.c | 248 +++++++++++++++++++++++++++++++++++++++++---------- fs/lockd/svcproc.c | 250 +++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 398 insertions(+), 100 deletions(-) (limited to 'fs') diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index e4d3f783e06a..fa41dda39925 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -486,65 +486,215 @@ nlm4svc_proc_granted_res(struct svc_rqst *rqstp) return rpc_success; } +static __be32 +nlm4svc_proc_unused(struct svc_rqst *rqstp) +{ + return rpc_proc_unavail; +} + /* * NLM Server procedures. */ -#define nlm4svc_encode_norep nlm4svc_encode_void -#define nlm4svc_decode_norep nlm4svc_decode_void -#define nlm4svc_decode_testres nlm4svc_decode_void -#define nlm4svc_decode_lockres nlm4svc_decode_void -#define nlm4svc_decode_unlockres nlm4svc_decode_void -#define nlm4svc_decode_cancelres nlm4svc_decode_void -#define nlm4svc_decode_grantedres nlm4svc_decode_void - -#define nlm4svc_proc_none nlm4svc_proc_null -#define nlm4svc_proc_test_res nlm4svc_proc_null -#define nlm4svc_proc_lock_res nlm4svc_proc_null -#define nlm4svc_proc_cancel_res nlm4svc_proc_null -#define nlm4svc_proc_unlock_res nlm4svc_proc_null - struct nlm_void { int dummy; }; -#define PROC(name, xargt, xrest, argt, rest, respsize) \ - { .pc_func = nlm4svc_proc_##name, \ - .pc_decode = nlm4svc_decode_##xargt, \ - .pc_encode = nlm4svc_encode_##xrest, \ - .pc_release = NULL, \ - .pc_argsize = sizeof(struct nlm_##argt), \ - .pc_ressize = sizeof(struct nlm_##rest), \ - .pc_xdrressize = respsize, \ - } #define Ck (1+XDR_QUADLEN(NLM_MAXCOOKIELEN)) /* cookie */ #define No (1+1024/4) /* netobj */ #define St 1 /* status */ #define Rg 4 /* range (offset + length) */ -const struct svc_procedure nlmsvc_procedures4[] = { - PROC(null, void, void, void, void, 1), - PROC(test, testargs, testres, args, res, Ck+St+2+No+Rg), - PROC(lock, lockargs, res, args, res, Ck+St), - PROC(cancel, cancargs, res, args, res, Ck+St), - PROC(unlock, unlockargs, res, args, res, Ck+St), - PROC(granted, testargs, res, args, res, Ck+St), - PROC(test_msg, testargs, norep, args, void, 1), - PROC(lock_msg, lockargs, norep, args, void, 1), - PROC(cancel_msg, cancargs, norep, args, void, 1), - PROC(unlock_msg, unlockargs, norep, args, void, 1), - PROC(granted_msg, testargs, norep, args, void, 1), - PROC(test_res, testres, norep, res, void, 1), - PROC(lock_res, lockres, norep, res, void, 1), - PROC(cancel_res, cancelres, norep, res, void, 1), - PROC(unlock_res, unlockres, norep, res, void, 1), - PROC(granted_res, res, norep, res, void, 1), - /* statd callback */ - PROC(sm_notify, reboot, void, reboot, void, 1), - PROC(none, void, void, void, void, 0), - PROC(none, void, void, void, void, 0), - PROC(none, void, void, void, void, 0), - PROC(share, shareargs, shareres, args, res, Ck+St+1), - PROC(unshare, shareargs, shareres, args, res, Ck+St+1), - PROC(nm_lock, lockargs, res, args, res, Ck+St), - PROC(free_all, notify, void, args, void, 1), +const struct svc_procedure nlmsvc_procedures4[24] = { + [NLMPROC_NULL] = { + .pc_func = nlm4svc_proc_null, + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_TEST] = { + .pc_func = nlm4svc_proc_test, + .pc_decode = nlm4svc_decode_testargs, + .pc_encode = nlm4svc_encode_testres, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+2+No+Rg, + }, + [NLMPROC_LOCK] = { + .pc_func = nlm4svc_proc_lock, + .pc_decode = nlm4svc_decode_lockargs, + .pc_encode = nlm4svc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + }, + [NLMPROC_CANCEL] = { + .pc_func = nlm4svc_proc_cancel, + .pc_decode = nlm4svc_decode_cancargs, + .pc_encode = nlm4svc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + }, + [NLMPROC_UNLOCK] = { + .pc_func = nlm4svc_proc_unlock, + .pc_decode = nlm4svc_decode_unlockargs, + .pc_encode = nlm4svc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + }, + [NLMPROC_GRANTED] = { + .pc_func = nlm4svc_proc_granted, + .pc_decode = nlm4svc_decode_testargs, + .pc_encode = nlm4svc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + }, + [NLMPROC_TEST_MSG] = { + .pc_func = nlm4svc_proc_test_msg, + .pc_decode = nlm4svc_decode_testargs, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_LOCK_MSG] = { + .pc_func = nlm4svc_proc_lock_msg, + .pc_decode = nlm4svc_decode_lockargs, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_CANCEL_MSG] = { + .pc_func = nlm4svc_proc_cancel_msg, + .pc_decode = nlm4svc_decode_cancargs, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_UNLOCK_MSG] = { + .pc_func = nlm4svc_proc_unlock_msg, + .pc_decode = nlm4svc_decode_unlockargs, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_GRANTED_MSG] = { + .pc_func = nlm4svc_proc_granted_msg, + .pc_decode = nlm4svc_decode_testargs, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_TEST_RES] = { + .pc_func = nlm4svc_proc_null, + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_LOCK_RES] = { + .pc_func = nlm4svc_proc_null, + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_CANCEL_RES] = { + .pc_func = nlm4svc_proc_null, + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_UNLOCK_RES] = { + .pc_func = nlm4svc_proc_null, + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_GRANTED_RES] = { + .pc_func = nlm4svc_proc_granted_res, + .pc_decode = nlm4svc_decode_res, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_NSM_NOTIFY] = { + .pc_func = nlm4svc_proc_sm_notify, + .pc_decode = nlm4svc_decode_reboot, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_reboot), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [17] = { + .pc_func = nlm4svc_proc_unused, + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = 0, + }, + [18] = { + .pc_func = nlm4svc_proc_unused, + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = 0, + }, + [19] = { + .pc_func = nlm4svc_proc_unused, + .pc_decode = nlm4svc_decode_void, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = 0, + }, + [NLMPROC_SHARE] = { + .pc_func = nlm4svc_proc_share, + .pc_decode = nlm4svc_decode_shareargs, + .pc_encode = nlm4svc_encode_shareres, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+1, + }, + [NLMPROC_UNSHARE] = { + .pc_func = nlm4svc_proc_unshare, + .pc_decode = nlm4svc_decode_shareargs, + .pc_encode = nlm4svc_encode_shareres, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+1, + }, + [NLMPROC_NM_LOCK] = { + .pc_func = nlm4svc_proc_nm_lock, + .pc_decode = nlm4svc_decode_lockargs, + .pc_encode = nlm4svc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + }, + [NLMPROC_FREE_ALL] = { + .pc_func = nlm4svc_proc_free_all, + .pc_decode = nlm4svc_decode_notify, + .pc_encode = nlm4svc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, }; diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index d0bb7a6bf005..50855f2c1f4b 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -529,66 +529,214 @@ nlmsvc_proc_granted_res(struct svc_rqst *rqstp) return rpc_success; } +static __be32 +nlmsvc_proc_unused(struct svc_rqst *rqstp) +{ + return rpc_proc_unavail; +} + /* * NLM Server procedures. */ -#define nlmsvc_encode_norep nlmsvc_encode_void -#define nlmsvc_decode_norep nlmsvc_decode_void -#define nlmsvc_decode_testres nlmsvc_decode_void -#define nlmsvc_decode_lockres nlmsvc_decode_void -#define nlmsvc_decode_unlockres nlmsvc_decode_void -#define nlmsvc_decode_cancelres nlmsvc_decode_void -#define nlmsvc_decode_grantedres nlmsvc_decode_void - -#define nlmsvc_proc_none nlmsvc_proc_null -#define nlmsvc_proc_test_res nlmsvc_proc_null -#define nlmsvc_proc_lock_res nlmsvc_proc_null -#define nlmsvc_proc_cancel_res nlmsvc_proc_null -#define nlmsvc_proc_unlock_res nlmsvc_proc_null - struct nlm_void { int dummy; }; -#define PROC(name, xargt, xrest, argt, rest, respsize) \ - { .pc_func = nlmsvc_proc_##name, \ - .pc_decode = nlmsvc_decode_##xargt, \ - .pc_encode = nlmsvc_encode_##xrest, \ - .pc_release = NULL, \ - .pc_argsize = sizeof(struct nlm_##argt), \ - .pc_ressize = sizeof(struct nlm_##rest), \ - .pc_xdrressize = respsize, \ - } - #define Ck (1+XDR_QUADLEN(NLM_MAXCOOKIELEN)) /* cookie */ #define St 1 /* status */ #define No (1+1024/4) /* Net Obj */ #define Rg 2 /* range - offset + size */ -const struct svc_procedure nlmsvc_procedures[] = { - PROC(null, void, void, void, void, 1), - PROC(test, testargs, testres, args, res, Ck+St+2+No+Rg), - PROC(lock, lockargs, res, args, res, Ck+St), - PROC(cancel, cancargs, res, args, res, Ck+St), - PROC(unlock, unlockargs, res, args, res, Ck+St), - PROC(granted, testargs, res, args, res, Ck+St), - PROC(test_msg, testargs, norep, args, void, 1), - PROC(lock_msg, lockargs, norep, args, void, 1), - PROC(cancel_msg, cancargs, norep, args, void, 1), - PROC(unlock_msg, unlockargs, norep, args, void, 1), - PROC(granted_msg, testargs, norep, args, void, 1), - PROC(test_res, testres, norep, res, void, 1), - PROC(lock_res, lockres, norep, res, void, 1), - PROC(cancel_res, cancelres, norep, res, void, 1), - PROC(unlock_res, unlockres, norep, res, void, 1), - PROC(granted_res, res, norep, res, void, 1), - /* statd callback */ - PROC(sm_notify, reboot, void, reboot, void, 1), - PROC(none, void, void, void, void, 1), - PROC(none, void, void, void, void, 1), - PROC(none, void, void, void, void, 1), - PROC(share, shareargs, shareres, args, res, Ck+St+1), - PROC(unshare, shareargs, shareres, args, res, Ck+St+1), - PROC(nm_lock, lockargs, res, args, res, Ck+St), - PROC(free_all, notify, void, args, void, 0), - +const struct svc_procedure nlmsvc_procedures[24] = { + [NLMPROC_NULL] = { + .pc_func = nlmsvc_proc_null, + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_TEST] = { + .pc_func = nlmsvc_proc_test, + .pc_decode = nlmsvc_decode_testargs, + .pc_encode = nlmsvc_encode_testres, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+2+No+Rg, + }, + [NLMPROC_LOCK] = { + .pc_func = nlmsvc_proc_lock, + .pc_decode = nlmsvc_decode_lockargs, + .pc_encode = nlmsvc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + }, + [NLMPROC_CANCEL] = { + .pc_func = nlmsvc_proc_cancel, + .pc_decode = nlmsvc_decode_cancargs, + .pc_encode = nlmsvc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + }, + [NLMPROC_UNLOCK] = { + .pc_func = nlmsvc_proc_unlock, + .pc_decode = nlmsvc_decode_unlockargs, + .pc_encode = nlmsvc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + }, + [NLMPROC_GRANTED] = { + .pc_func = nlmsvc_proc_granted, + .pc_decode = nlmsvc_decode_testargs, + .pc_encode = nlmsvc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + }, + [NLMPROC_TEST_MSG] = { + .pc_func = nlmsvc_proc_test_msg, + .pc_decode = nlmsvc_decode_testargs, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_LOCK_MSG] = { + .pc_func = nlmsvc_proc_lock_msg, + .pc_decode = nlmsvc_decode_lockargs, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_CANCEL_MSG] = { + .pc_func = nlmsvc_proc_cancel_msg, + .pc_decode = nlmsvc_decode_cancargs, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_UNLOCK_MSG] = { + .pc_func = nlmsvc_proc_unlock_msg, + .pc_decode = nlmsvc_decode_unlockargs, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_GRANTED_MSG] = { + .pc_func = nlmsvc_proc_granted_msg, + .pc_decode = nlmsvc_decode_testargs, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_TEST_RES] = { + .pc_func = nlmsvc_proc_null, + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_LOCK_RES] = { + .pc_func = nlmsvc_proc_null, + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_CANCEL_RES] = { + .pc_func = nlmsvc_proc_null, + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_UNLOCK_RES] = { + .pc_func = nlmsvc_proc_null, + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_GRANTED_RES] = { + .pc_func = nlmsvc_proc_granted_res, + .pc_decode = nlmsvc_decode_res, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_res), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_NSM_NOTIFY] = { + .pc_func = nlmsvc_proc_sm_notify, + .pc_decode = nlmsvc_decode_reboot, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_reboot), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [17] = { + .pc_func = nlmsvc_proc_unused, + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [18] = { + .pc_func = nlmsvc_proc_unused, + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [19] = { + .pc_func = nlmsvc_proc_unused, + .pc_decode = nlmsvc_decode_void, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_void), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = St, + }, + [NLMPROC_SHARE] = { + .pc_func = nlmsvc_proc_share, + .pc_decode = nlmsvc_decode_shareargs, + .pc_encode = nlmsvc_encode_shareres, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+1, + }, + [NLMPROC_UNSHARE] = { + .pc_func = nlmsvc_proc_unshare, + .pc_decode = nlmsvc_decode_shareargs, + .pc_encode = nlmsvc_encode_shareres, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St+1, + }, + [NLMPROC_NM_LOCK] = { + .pc_func = nlmsvc_proc_nm_lock, + .pc_decode = nlmsvc_decode_lockargs, + .pc_encode = nlmsvc_encode_res, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_res), + .pc_xdrressize = Ck+St, + }, + [NLMPROC_FREE_ALL] = { + .pc_func = nlmsvc_proc_free_all, + .pc_decode = nlmsvc_decode_notify, + .pc_encode = nlmsvc_encode_void, + .pc_argsize = sizeof(struct nlm_args), + .pc_ressize = sizeof(struct nlm_void), + .pc_xdrressize = 0, + }, }; -- cgit From ba1df797e5bbba68ddd1a29bd658b1c11f9a60b6 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 1 Oct 2020 18:59:07 -0400 Subject: NFSACL: Replace PROC() macro with open code Clean up: Follow-up on ten-year-old commit b9081d90f5b9 ("NFS: kill off complicated macro 'PROC'") by performing the same conversion in the NFSACL code. To reduce the chance of error, I copied the original C preprocessor output and then made some minor edits. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs2acl.c | 72 +++++++++++++++++++++++++++++++++++++------------------ fs/nfsd/nfs3acl.c | 49 +++++++++++++++++++++---------------- 2 files changed, 78 insertions(+), 43 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index cbab1d2d8a75..8d20e0d74417 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -347,36 +347,62 @@ static void nfsaclsvc_release_access(struct svc_rqst *rqstp) fh_put(&resp->fh); } -#define nfsaclsvc_decode_voidargs NULL -#define nfsaclsvc_release_void NULL -#define nfsd3_fhandleargs nfsd_fhandle -#define nfsd3_attrstatres nfsd_attrstat -#define nfsd3_voidres nfsd3_voidargs struct nfsd3_voidargs { int dummy; }; -#define PROC(name, argt, rest, relt, cache, respsize) \ -{ \ - .pc_func = nfsacld_proc_##name, \ - .pc_decode = nfsaclsvc_decode_##argt##args, \ - .pc_encode = nfsaclsvc_encode_##rest##res, \ - .pc_release = nfsaclsvc_release_##relt, \ - .pc_argsize = sizeof(struct nfsd3_##argt##args), \ - .pc_ressize = sizeof(struct nfsd3_##rest##res), \ - .pc_cachetype = cache, \ - .pc_xdrressize = respsize, \ -} - #define ST 1 /* status*/ #define AT 21 /* attributes */ #define pAT (1+AT) /* post attributes - conditional */ #define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */ -static const struct svc_procedure nfsd_acl_procedures2[] = { - PROC(null, void, void, void, RC_NOCACHE, ST), - PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)), - PROC(setacl, setacl, attrstat, attrstat, RC_NOCACHE, ST+AT), - PROC(getattr, fhandle, attrstat, attrstat, RC_NOCACHE, ST+AT), - PROC(access, access, access, access, RC_NOCACHE, ST+AT+1), +static const struct svc_procedure nfsd_acl_procedures2[5] = { + [ACLPROC2_NULL] = { + .pc_func = nfsacld_proc_null, + .pc_encode = nfsaclsvc_encode_voidres, + .pc_argsize = sizeof(struct nfsd3_voidargs), + .pc_ressize = sizeof(struct nfsd3_voidargs), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST, + }, + [ACLPROC2_GETACL] = { + .pc_func = nfsacld_proc_getacl, + .pc_decode = nfsaclsvc_decode_getaclargs, + .pc_encode = nfsaclsvc_encode_getaclres, + .pc_release = nfsaclsvc_release_getacl, + .pc_argsize = sizeof(struct nfsd3_getaclargs), + .pc_ressize = sizeof(struct nfsd3_getaclres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+1+2*(1+ACL), + }, + [ACLPROC2_SETACL] = { + .pc_func = nfsacld_proc_setacl, + .pc_decode = nfsaclsvc_decode_setaclargs, + .pc_encode = nfsaclsvc_encode_attrstatres, + .pc_release = nfsaclsvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd3_setaclargs), + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+AT, + }, + [ACLPROC2_GETATTR] = { + .pc_func = nfsacld_proc_getattr, + .pc_decode = nfsaclsvc_decode_fhandleargs, + .pc_encode = nfsaclsvc_encode_attrstatres, + .pc_release = nfsaclsvc_release_attrstat, + .pc_argsize = sizeof(struct nfsd_fhandle), + .pc_ressize = sizeof(struct nfsd_attrstat), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+AT, + }, + [ACLPROC2_ACCESS] = { + .pc_func = nfsacld_proc_access, + .pc_decode = nfsaclsvc_decode_accessargs, + .pc_encode = nfsaclsvc_encode_accessres, + .pc_release = nfsaclsvc_release_access, + .pc_argsize = sizeof(struct nfsd3_accessargs), + .pc_ressize = sizeof(struct nfsd3_accessres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+AT+1, + }, }; static unsigned int nfsd_acl_count2[ARRAY_SIZE(nfsd_acl_procedures2)]; diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index 13bca4a2f89d..292acb2e529c 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -235,33 +235,42 @@ static void nfs3svc_release_getacl(struct svc_rqst *rqstp) posix_acl_release(resp->acl_default); } -#define nfs3svc_decode_voidargs NULL -#define nfs3svc_release_void NULL -#define nfsd3_setaclres nfsd3_attrstat -#define nfsd3_voidres nfsd3_voidargs struct nfsd3_voidargs { int dummy; }; -#define PROC(name, argt, rest, relt, cache, respsize) \ -{ \ - .pc_func = nfsd3_proc_##name, \ - .pc_decode = nfs3svc_decode_##argt##args, \ - .pc_encode = nfs3svc_encode_##rest##res, \ - .pc_release = nfs3svc_release_##relt, \ - .pc_argsize = sizeof(struct nfsd3_##argt##args), \ - .pc_ressize = sizeof(struct nfsd3_##rest##res), \ - .pc_cachetype = cache, \ - .pc_xdrressize = respsize, \ -} - #define ST 1 /* status*/ #define AT 21 /* attributes */ #define pAT (1+AT) /* post attributes - conditional */ #define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */ -static const struct svc_procedure nfsd_acl_procedures3[] = { - PROC(null, void, void, void, RC_NOCACHE, ST), - PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)), - PROC(setacl, setacl, setacl, fhandle, RC_NOCACHE, ST+pAT), +static const struct svc_procedure nfsd_acl_procedures3[3] = { + [ACLPROC3_NULL] = { + .pc_func = nfsd3_proc_null, + .pc_encode = nfs3svc_encode_voidres, + .pc_argsize = sizeof(struct nfsd3_voidargs), + .pc_ressize = sizeof(struct nfsd3_voidargs), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST, + }, + [ACLPROC3_GETACL] = { + .pc_func = nfsd3_proc_getacl, + .pc_decode = nfs3svc_decode_getaclargs, + .pc_encode = nfs3svc_encode_getaclres, + .pc_release = nfs3svc_release_getacl, + .pc_argsize = sizeof(struct nfsd3_getaclargs), + .pc_ressize = sizeof(struct nfsd3_getaclres), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+1+2*(1+ACL), + }, + [ACLPROC3_SETACL] = { + .pc_func = nfsd3_proc_setacl, + .pc_decode = nfs3svc_decode_setaclargs, + .pc_encode = nfs3svc_encode_setaclres, + .pc_release = nfs3svc_release_fhandle, + .pc_argsize = sizeof(struct nfsd3_setaclargs), + .pc_ressize = sizeof(struct nfsd3_attrstat), + .pc_cachetype = RC_NOCACHE, + .pc_xdrressize = ST+pAT, + }, }; static unsigned int nfsd_acl_count3[ARRAY_SIZE(nfsd_acl_procedures3)]; -- cgit From dcc46991d3c5b30a3944578511f9a51a71cc0078 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 1 Oct 2020 18:59:12 -0400 Subject: NFSD: Encoder and decoder functions are always present nfsd_dispatch() is a hot path. Let's optimize the XDR method calls for the by-far common case, which is that the XDR methods are indeed present. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs2acl.c | 6 ++++++ fs/nfsd/nfs3acl.c | 1 + fs/nfsd/nfs3proc.c | 1 + fs/nfsd/nfs3xdr.c | 6 ++++++ fs/nfsd/nfs4proc.c | 1 + fs/nfsd/nfs4xdr.c | 6 ++++++ fs/nfsd/nfssvc.c | 5 ++--- fs/nfsd/xdr3.h | 1 + fs/nfsd/xdr4.h | 1 + 9 files changed, 25 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 8d20e0d74417..3c8b9250dc4a 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -183,6 +183,11 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp) /* * XDR decode functions */ +static int nfsaclsvc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p) +{ + return 1; +} + static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_getaclargs *argp = rqstp->rq_argp; @@ -357,6 +362,7 @@ struct nfsd3_voidargs { int dummy; }; static const struct svc_procedure nfsd_acl_procedures2[5] = { [ACLPROC2_NULL] = { .pc_func = nfsacld_proc_null, + .pc_decode = nfsaclsvc_decode_voidarg, .pc_encode = nfsaclsvc_encode_voidres, .pc_argsize = sizeof(struct nfsd3_voidargs), .pc_ressize = sizeof(struct nfsd3_voidargs), diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index 292acb2e529c..614168675c17 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -245,6 +245,7 @@ struct nfsd3_voidargs { int dummy; }; static const struct svc_procedure nfsd_acl_procedures3[3] = { [ACLPROC3_NULL] = { .pc_func = nfsd3_proc_null, + .pc_decode = nfs3svc_decode_voidarg, .pc_encode = nfs3svc_encode_voidres, .pc_argsize = sizeof(struct nfsd3_voidargs), .pc_ressize = sizeof(struct nfsd3_voidargs), diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 288bc76b4574..3d09959c7042 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -716,6 +716,7 @@ struct nfsd3_voidargs { int dummy; }; static const struct svc_procedure nfsd_procedures3[22] = { [NFS3PROC_NULL] = { .pc_func = nfsd3_proc_null, + .pc_decode = nfs3svc_decode_voidarg, .pc_encode = nfs3svc_encode_voidres, .pc_argsize = sizeof(struct nfsd3_voidargs), .pc_ressize = sizeof(struct nfsd3_voidres), diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index aae514d40b64..e540fd1a29d8 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -304,6 +304,12 @@ void fill_post_wcc(struct svc_fh *fhp) /* * XDR decode functions */ +int +nfs3svc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p) +{ + return 1; +} + int nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p) { diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 63e5a4844d8c..578fc9f4e3d1 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -3279,6 +3279,7 @@ struct nfsd4_voidargs { int dummy; }; static const struct svc_procedure nfsd_procedures4[2] = { [NFSPROC4_NULL] = { .pc_func = nfsd4_proc_null, + .pc_decode = nfs4svc_decode_voidarg, .pc_encode = nfs4svc_encode_voidres, .pc_argsize = sizeof(struct nfsd4_voidargs), .pc_ressize = sizeof(struct nfsd4_voidres), diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index c11943a0c1db..c28d908d7a15 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -5134,6 +5134,12 @@ void nfsd4_release_compoundargs(struct svc_rqst *rqstp) } } +int +nfs4svc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p) +{ + return 1; +} + int nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p) { diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index f6bc94cab9da..b2d20920a998 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -1022,8 +1022,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) */ rqstp->rq_cachetype = proc->pc_cachetype; /* Decode arguments */ - if (proc->pc_decode && - !proc->pc_decode(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base)) { + if (!proc->pc_decode(rqstp, (__be32 *)rqstp->rq_arg.head[0].iov_base)) { dprintk("nfsd: failed to decode arguments!\n"); *statp = rpc_garbage_args; return 1; @@ -1062,7 +1061,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) * For NFSv2, additional info is never returned in case of an error. */ if (!(nfserr && rqstp->rq_vers == 2)) { - if (proc->pc_encode && !proc->pc_encode(rqstp, nfserrp)) { + if (!proc->pc_encode(rqstp, nfserrp)) { /* Failed to encode result. Release cache entry */ dprintk("nfsd: failed to encode result!\n"); nfsd_cache_update(rqstp, RC_NOCACHE, NULL); diff --git a/fs/nfsd/xdr3.h b/fs/nfsd/xdr3.h index 4155fd71714c..ae6fa6c9cb46 100644 --- a/fs/nfsd/xdr3.h +++ b/fs/nfsd/xdr3.h @@ -273,6 +273,7 @@ union nfsd3_xdrstore { #define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore) +int nfs3svc_decode_voidarg(struct svc_rqst *, __be32 *); int nfs3svc_decode_fhandle(struct svc_rqst *, __be32 *); int nfs3svc_decode_sattrargs(struct svc_rqst *, __be32 *); int nfs3svc_decode_diropargs(struct svc_rqst *, __be32 *); diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h index 66499fb6b567..679d40af1bbb 100644 --- a/fs/nfsd/xdr4.h +++ b/fs/nfsd/xdr4.h @@ -781,6 +781,7 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp) bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp); +int nfs4svc_decode_voidarg(struct svc_rqst *, __be32 *); int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *); int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *); int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *); -- cgit From 84c138e78d8ec247737d2c9e8dba50f20eb01a60 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 1 Oct 2020 18:59:18 -0400 Subject: NFSD: Clean up switch statement in nfsd_dispatch() Reorder the arms so the compiler places checks for the most frequent case first. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfssvc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index b2d20920a998..3cdefb2294ce 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -1030,12 +1030,12 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) /* Check whether we have this call in the cache. */ switch (nfsd_cache_lookup(rqstp)) { - case RC_DROPIT: - return 0; + case RC_DOIT: + break; case RC_REPLY: return 1; - case RC_DOIT:; - /* do it */ + case RC_DROPIT: + return 0; } /* need to grab the location to store the status, as -- cgit From 383c440d4f14ffcda32227c4de23af8a352223c1 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 1 Oct 2020 18:59:23 -0400 Subject: NFSD: Clean up stale comments in nfsd_dispatch() Add a documenting comment for the function. Remove comments that simply describe obvious aspects of the code, but leave comments that explain the differences in processing of each NFS version. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfssvc.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 3cdefb2294ce..9be2e14b3bca 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -1000,8 +1000,18 @@ static bool nfs_request_too_big(struct svc_rqst *rqstp, return rqstp->rq_arg.len > PAGE_SIZE; } -int -nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) +/** + * nfsd_dispatch - Process an NFS or NFSACL Request + * @rqstp: incoming request + * @statp: pointer to location of accept_stat field in RPC Reply buffer + * + * This RPC dispatcher integrates the NFS server's duplicate reply cache. + * + * Return values: + * %0: Processing complete; do not send a Reply + * %1: Processing complete; send Reply in rqstp->rq_res + */ +int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) { const struct svc_procedure *proc; __be32 nfserr; @@ -1021,14 +1031,12 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) * (necessary in the NFSv4.0 compound case) */ rqstp->rq_cachetype = proc->pc_cachetype; - /* Decode arguments */ if (!proc->pc_decode(rqstp, (__be32 *)rqstp->rq_arg.head[0].iov_base)) { dprintk("nfsd: failed to decode arguments!\n"); *statp = rpc_garbage_args; return 1; } - /* Check whether we have this call in the cache. */ switch (nfsd_cache_lookup(rqstp)) { case RC_DOIT: break; @@ -1038,14 +1046,14 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) return 0; } - /* need to grab the location to store the status, as - * nfsv4 does some encoding while processing + /* + * Need to grab the location to store the status, as + * NFSv4 does some encoding while processing */ nfserrp = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len; rqstp->rq_res.head[0].iov_len += sizeof(__be32); - /* Now call the procedure handler, and encode NFS status. */ nfserr = proc->pc_func(rqstp); nfserr = map_new_errors(rqstp->rq_vers, nfserr); if (nfserr == nfserr_dropit || test_bit(RQ_DROPME, &rqstp->rq_flags)) { @@ -1057,12 +1065,11 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) if (rqstp->rq_proc != 0) *nfserrp++ = nfserr; - /* Encode result. + /* * For NFSv2, additional info is never returned in case of an error. */ if (!(nfserr && rqstp->rq_vers == 2)) { if (!proc->pc_encode(rqstp, nfserrp)) { - /* Failed to encode result. Release cache entry */ dprintk("nfsd: failed to encode result!\n"); nfsd_cache_update(rqstp, RC_NOCACHE, NULL); *statp = rpc_system_err; @@ -1070,7 +1077,6 @@ nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) } } - /* Store reply in cache. */ nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1); return 1; } -- cgit From 4c96cb56eefa6ae5147a40441a20d3f6a7aef31c Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 1 Oct 2020 18:59:28 -0400 Subject: NFSD: Clean up nfsd_dispatch() variables For consistency and code legibility, use a similar organization of variables as svc_generic_dispatch(). Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfssvc.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 9be2e14b3bca..aa516838ce0b 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -1013,13 +1013,13 @@ static bool nfs_request_too_big(struct svc_rqst *rqstp, */ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) { - const struct svc_procedure *proc; - __be32 nfserr; - __be32 *nfserrp; + const struct svc_procedure *proc = rqstp->rq_procinfo; + struct kvec *argv = &rqstp->rq_arg.head[0]; + struct kvec *resv = &rqstp->rq_res.head[0]; + __be32 nfserr, *nfserrp; dprintk("nfsd_dispatch: vers %d proc %d\n", rqstp->rq_vers, rqstp->rq_proc); - proc = rqstp->rq_procinfo; if (nfs_request_too_big(rqstp, proc)) { dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers); @@ -1031,7 +1031,7 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) * (necessary in the NFSv4.0 compound case) */ rqstp->rq_cachetype = proc->pc_cachetype; - if (!proc->pc_decode(rqstp, (__be32 *)rqstp->rq_arg.head[0].iov_base)) { + if (!proc->pc_decode(rqstp, argv->iov_base)) { dprintk("nfsd: failed to decode arguments!\n"); *statp = rpc_garbage_args; return 1; @@ -1050,9 +1050,8 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) * Need to grab the location to store the status, as * NFSv4 does some encoding while processing */ - nfserrp = rqstp->rq_res.head[0].iov_base - + rqstp->rq_res.head[0].iov_len; - rqstp->rq_res.head[0].iov_len += sizeof(__be32); + nfserrp = resv->iov_base + resv->iov_len; + resv->iov_len += sizeof(__be32); nfserr = proc->pc_func(rqstp); nfserr = map_new_errors(rqstp->rq_vers, nfserr); -- cgit From 85085aacefc62fe58f89fdcf695e2d1155ff45d9 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 1 Oct 2020 18:59:33 -0400 Subject: NFSD: Refactor nfsd_dispatch() error paths nfsd_dispatch() is a hot path. Ensure the compiler takes the processing of rare error cases out of line. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfssvc.c | 60 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 35 insertions(+), 25 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index aa516838ce0b..e793344227c9 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -1021,29 +1021,24 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) dprintk("nfsd_dispatch: vers %d proc %d\n", rqstp->rq_vers, rqstp->rq_proc); - if (nfs_request_too_big(rqstp, proc)) { - dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers); - *statp = rpc_garbage_args; - return 1; - } + if (nfs_request_too_big(rqstp, proc)) + goto out_too_large; + /* * Give the xdr decoder a chance to change this if it wants * (necessary in the NFSv4.0 compound case) */ rqstp->rq_cachetype = proc->pc_cachetype; - if (!proc->pc_decode(rqstp, argv->iov_base)) { - dprintk("nfsd: failed to decode arguments!\n"); - *statp = rpc_garbage_args; - return 1; - } + if (!proc->pc_decode(rqstp, argv->iov_base)) + goto out_decode_err; switch (nfsd_cache_lookup(rqstp)) { case RC_DOIT: break; case RC_REPLY: - return 1; + goto out_cached_reply; case RC_DROPIT: - return 0; + goto out_dropit; } /* @@ -1055,11 +1050,8 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) nfserr = proc->pc_func(rqstp); nfserr = map_new_errors(rqstp->rq_vers, nfserr); - if (nfserr == nfserr_dropit || test_bit(RQ_DROPME, &rqstp->rq_flags)) { - dprintk("nfsd: Dropping request; may be revisited later\n"); - nfsd_cache_update(rqstp, RC_NOCACHE, NULL); - return 0; - } + if (nfserr == nfserr_dropit || test_bit(RQ_DROPME, &rqstp->rq_flags)) + goto out_update_drop; if (rqstp->rq_proc != 0) *nfserrp++ = nfserr; @@ -1067,16 +1059,34 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) /* * For NFSv2, additional info is never returned in case of an error. */ - if (!(nfserr && rqstp->rq_vers == 2)) { - if (!proc->pc_encode(rqstp, nfserrp)) { - dprintk("nfsd: failed to encode result!\n"); - nfsd_cache_update(rqstp, RC_NOCACHE, NULL); - *statp = rpc_system_err; - return 1; - } - } + if (!(nfserr && rqstp->rq_vers == 2)) + if (!proc->pc_encode(rqstp, nfserrp)) + goto out_encode_err; nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1); +out_cached_reply: + return 1; + +out_too_large: + dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers); + *statp = rpc_garbage_args; + return 1; + +out_decode_err: + dprintk("nfsd: failed to decode arguments!\n"); + *statp = rpc_garbage_args; + return 1; + +out_update_drop: + dprintk("nfsd: Dropping request; may be revisited later\n"); + nfsd_cache_update(rqstp, RC_NOCACHE, NULL); +out_dropit: + return 0; + +out_encode_err: + dprintk("nfsd: failed to encode result!\n"); + nfsd_cache_update(rqstp, RC_NOCACHE, NULL); + *statp = rpc_system_err; return 1; } -- cgit From 7cf8357043bb828444cd9f4296f595bdbf68fa87 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 1 Oct 2020 18:59:38 -0400 Subject: NFSD: Remove vestigial typedefs Clean up: These are not used. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfsproc.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 6d1b3af40a4f..2a4c4178acf1 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -11,9 +11,6 @@ #include "xdr.h" #include "vfs.h" -typedef struct svc_rqst svc_rqst; -typedef struct svc_buf svc_buf; - #define NFSDDBG_FACILITY NFSDDBG_PROC -- cgit From 1841b9b61492e35234bdca8a5737a0e5df770f27 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 1 Oct 2020 18:59:44 -0400 Subject: NFSD: Fix .pc_release method for NFSv2 nfsd_release_fhandle() assumes that rqstp->rq_resp always points to an nfsd_fhandle struct. In fact, no NFSv2 procedure uses struct nfsd_fhandle as its response structure. So far that has been "safe" to do because the res structs put the resp->fh field at that same offset as struct nfsd_fhandle. I don't think that's a guarantee, though, and there is certainly nothing preventing a developer from altering the fields in those structures. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfsproc.c | 14 +++++++------- fs/nfsd/nfsxdr.c | 19 ++++++++++++++++--- fs/nfsd/xdr.h | 4 +++- 3 files changed, 26 insertions(+), 11 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 2a4c4178acf1..c349e1dac3ff 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -611,7 +611,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { .pc_func = nfsd_proc_getattr, .pc_decode = nfssvc_decode_fhandle, .pc_encode = nfssvc_encode_attrstat, - .pc_release = nfssvc_release_fhandle, + .pc_release = nfssvc_release_attrstat, .pc_argsize = sizeof(struct nfsd_fhandle), .pc_ressize = sizeof(struct nfsd_attrstat), .pc_cachetype = RC_NOCACHE, @@ -621,7 +621,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { .pc_func = nfsd_proc_setattr, .pc_decode = nfssvc_decode_sattrargs, .pc_encode = nfssvc_encode_attrstat, - .pc_release = nfssvc_release_fhandle, + .pc_release = nfssvc_release_attrstat, .pc_argsize = sizeof(struct nfsd_sattrargs), .pc_ressize = sizeof(struct nfsd_attrstat), .pc_cachetype = RC_REPLBUFF, @@ -640,7 +640,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { .pc_func = nfsd_proc_lookup, .pc_decode = nfssvc_decode_diropargs, .pc_encode = nfssvc_encode_diropres, - .pc_release = nfssvc_release_fhandle, + .pc_release = nfssvc_release_diropres, .pc_argsize = sizeof(struct nfsd_diropargs), .pc_ressize = sizeof(struct nfsd_diropres), .pc_cachetype = RC_NOCACHE, @@ -659,7 +659,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { .pc_func = nfsd_proc_read, .pc_decode = nfssvc_decode_readargs, .pc_encode = nfssvc_encode_readres, - .pc_release = nfssvc_release_fhandle, + .pc_release = nfssvc_release_readres, .pc_argsize = sizeof(struct nfsd_readargs), .pc_ressize = sizeof(struct nfsd_readres), .pc_cachetype = RC_NOCACHE, @@ -678,7 +678,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { .pc_func = nfsd_proc_write, .pc_decode = nfssvc_decode_writeargs, .pc_encode = nfssvc_encode_attrstat, - .pc_release = nfssvc_release_fhandle, + .pc_release = nfssvc_release_attrstat, .pc_argsize = sizeof(struct nfsd_writeargs), .pc_ressize = sizeof(struct nfsd_attrstat), .pc_cachetype = RC_REPLBUFF, @@ -688,7 +688,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { .pc_func = nfsd_proc_create, .pc_decode = nfssvc_decode_createargs, .pc_encode = nfssvc_encode_diropres, - .pc_release = nfssvc_release_fhandle, + .pc_release = nfssvc_release_diropres, .pc_argsize = sizeof(struct nfsd_createargs), .pc_ressize = sizeof(struct nfsd_diropres), .pc_cachetype = RC_REPLBUFF, @@ -734,7 +734,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { .pc_func = nfsd_proc_mkdir, .pc_decode = nfssvc_decode_createargs, .pc_encode = nfssvc_encode_diropres, - .pc_release = nfssvc_release_fhandle, + .pc_release = nfssvc_release_diropres, .pc_argsize = sizeof(struct nfsd_createargs), .pc_ressize = sizeof(struct nfsd_diropres), .pc_cachetype = RC_REPLBUFF, diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index b51fe515f06f..39c004ec7d85 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -561,10 +561,23 @@ nfssvc_encode_entry(void *ccdv, const char *name, /* * XDR release functions */ -void -nfssvc_release_fhandle(struct svc_rqst *rqstp) +void nfssvc_release_attrstat(struct svc_rqst *rqstp) { - struct nfsd_fhandle *resp = rqstp->rq_resp; + struct nfsd_attrstat *resp = rqstp->rq_resp; + + fh_put(&resp->fh); +} + +void nfssvc_release_diropres(struct svc_rqst *rqstp) +{ + struct nfsd_diropres *resp = rqstp->rq_resp; + + fh_put(&resp->fh); +} + +void nfssvc_release_readres(struct svc_rqst *rqstp) +{ + struct nfsd_readres *resp = rqstp->rq_resp; fh_put(&resp->fh); } diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h index ea7cca3a64b7..3d3e16d48268 100644 --- a/fs/nfsd/xdr.h +++ b/fs/nfsd/xdr.h @@ -156,7 +156,9 @@ int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *); int nfssvc_encode_entry(void *, const char *name, int namlen, loff_t offset, u64 ino, unsigned int); -void nfssvc_release_fhandle(struct svc_rqst *); +void nfssvc_release_attrstat(struct svc_rqst *rqstp); +void nfssvc_release_diropres(struct svc_rqst *rqstp); +void nfssvc_release_readres(struct svc_rqst *rqstp); /* Helper functions for NFSv2 ACL code */ __be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat); -- cgit From f0af22101d9072c6488b8d20d6e33338669029fe Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 1 Oct 2020 18:59:49 -0400 Subject: NFSD: Call NFSv2 encoders on error returns Remove special dispatcher logic for NFSv2 error responses. These are rare to the point of becoming extinct, but all NFS responses have to pay the cost of the extra conditional branches. With this change, the NFSv2 error cases now get proper xdr_ressize_check() calls. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs2acl.c | 75 ++++++++++++---------- fs/nfsd/nfsproc.c | 185 +++++++++++++++++++++++++++++------------------------- fs/nfsd/nfssvc.c | 8 +-- fs/nfsd/nfsxdr.c | 18 ++++++ fs/nfsd/xdr.h | 7 +++ 5 files changed, 171 insertions(+), 122 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 3c8b9250dc4a..6f46afdb0616 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -14,7 +14,6 @@ #include "vfs.h" #define NFSDDBG_FACILITY NFSDDBG_PROC -#define RETURN_STATUS(st) { resp->status = (st); return (st); } /* * NULL call. @@ -35,24 +34,25 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp) struct posix_acl *acl; struct inode *inode; svc_fh *fh; - __be32 nfserr = 0; dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); fh = fh_copy(&resp->fh, &argp->fh); - nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); - if (nfserr) - RETURN_STATUS(nfserr); + resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); + if (resp->status != nfs_ok) + goto out; inode = d_inode(fh->fh_dentry); - if (argp->mask & ~NFS_ACL_MASK) - RETURN_STATUS(nfserr_inval); + if (argp->mask & ~NFS_ACL_MASK) { + resp->status = nfserr_inval; + goto out; + } resp->mask = argp->mask; - nfserr = fh_getattr(fh, &resp->stat); - if (nfserr) - RETURN_STATUS(nfserr); + resp->status = fh_getattr(fh, &resp->stat); + if (resp->status != nfs_ok) + goto out; if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { acl = get_acl(inode, ACL_TYPE_ACCESS); @@ -61,7 +61,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp) acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); } if (IS_ERR(acl)) { - nfserr = nfserrno(PTR_ERR(acl)); + resp->status = nfserrno(PTR_ERR(acl)); goto fail; } resp->acl_access = acl; @@ -71,19 +71,20 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp) of a non-directory! */ acl = get_acl(inode, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) { - nfserr = nfserrno(PTR_ERR(acl)); + resp->status = nfserrno(PTR_ERR(acl)); goto fail; } resp->acl_default = acl; } /* resp->acl_{access,default} are released in nfssvc_release_getacl. */ - RETURN_STATUS(0); +out: + return resp->status; fail: posix_acl_release(resp->acl_access); posix_acl_release(resp->acl_default); - RETURN_STATUS(nfserr); + goto out; } /* @@ -95,14 +96,13 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp) struct nfsd_attrstat *resp = rqstp->rq_resp; struct inode *inode; svc_fh *fh; - __be32 nfserr = 0; int error; dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh)); fh = fh_copy(&resp->fh, &argp->fh); - nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); - if (nfserr) + resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); + if (resp->status != nfs_ok) goto out; inode = d_inode(fh->fh_dentry); @@ -124,19 +124,20 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp) fh_drop_write(fh); - nfserr = fh_getattr(fh, &resp->stat); + resp->status = fh_getattr(fh, &resp->stat); out: /* argp->acl_{access,default} may have been allocated in nfssvc_decode_setaclargs. */ posix_acl_release(argp->acl_access); posix_acl_release(argp->acl_default); - return nfserr; + return resp->status; + out_drop_lock: fh_unlock(fh); fh_drop_write(fh); out_errno: - nfserr = nfserrno(error); + resp->status = nfserrno(error); goto out; } @@ -147,15 +148,16 @@ static __be32 nfsacld_proc_getattr(struct svc_rqst *rqstp) { struct nfsd_fhandle *argp = rqstp->rq_argp; struct nfsd_attrstat *resp = rqstp->rq_resp; - __be32 nfserr; + dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); fh_copy(&resp->fh, &argp->fh); - nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); - if (nfserr) - return nfserr; - nfserr = fh_getattr(&resp->fh, &resp->stat); - return nfserr; + resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); + if (resp->status != nfs_ok) + goto out; + resp->status = fh_getattr(&resp->fh, &resp->stat); +out: + return resp->status; } /* @@ -165,7 +167,6 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp) { struct nfsd3_accessargs *argp = rqstp->rq_argp; struct nfsd3_accessres *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: ACCESS(2acl) %s 0x%x\n", SVCFH_fmt(&argp->fh), @@ -173,11 +174,12 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp) fh_copy(&resp->fh, &argp->fh); resp->access = argp->access; - nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL); - if (nfserr) - return nfserr; - nfserr = fh_getattr(&resp->fh, &resp->stat); - return nfserr; + resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL); + if (resp->status != nfs_ok) + goto out; + resp->status = fh_getattr(&resp->fh, &resp->stat); +out: + return resp->status; } /* @@ -273,6 +275,9 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) int n; int w; + if (resp->status != nfs_ok) + return xdr_ressize_check(rqstp, p); + /* * Since this is version 2, the check for nfserr in * nfsd_dispatch actually ensures the following cannot happen. @@ -312,6 +317,9 @@ static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd_attrstat *resp = rqstp->rq_resp; + if (resp->status != nfs_ok) + return xdr_ressize_check(rqstp, p); + p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat); return xdr_ressize_check(rqstp, p); } @@ -321,6 +329,9 @@ static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_accessres *resp = rqstp->rq_resp; + if (resp->status != nfs_ok) + return xdr_ressize_check(rqstp, p); + p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat); *p++ = htonl(resp->access); return xdr_ressize_check(rqstp, p); diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index c349e1dac3ff..526170319ecf 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -13,25 +13,12 @@ #define NFSDDBG_FACILITY NFSDDBG_PROC - static __be32 nfsd_proc_null(struct svc_rqst *rqstp) { return nfs_ok; } -static __be32 -nfsd_return_attrs(__be32 err, struct nfsd_attrstat *resp) -{ - if (err) return err; - return fh_getattr(&resp->fh, &resp->stat); -} -static __be32 -nfsd_return_dirop(__be32 err, struct nfsd_diropres *resp) -{ - if (err) return err; - return fh_getattr(&resp->fh, &resp->stat); -} /* * Get a file's attributes * N.B. After this call resp->fh needs an fh_put @@ -41,13 +28,17 @@ nfsd_proc_getattr(struct svc_rqst *rqstp) { struct nfsd_fhandle *argp = rqstp->rq_argp; struct nfsd_attrstat *resp = rqstp->rq_resp; - __be32 nfserr; + dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh)); fh_copy(&resp->fh, &argp->fh); - nfserr = fh_verify(rqstp, &resp->fh, 0, - NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT); - return nfsd_return_attrs(nfserr, resp); + resp->status = fh_verify(rqstp, &resp->fh, 0, + NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT); + if (resp->status != nfs_ok) + goto out; + resp->status = fh_getattr(&resp->fh, &resp->stat); +out: + return resp->status; } /* @@ -61,7 +52,6 @@ nfsd_proc_setattr(struct svc_rqst *rqstp) struct nfsd_attrstat *resp = rqstp->rq_resp; struct iattr *iap = &argp->attrs; struct svc_fh *fhp; - __be32 nfserr; dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n", SVCFH_fmt(&argp->fh), @@ -93,9 +83,9 @@ nfsd_proc_setattr(struct svc_rqst *rqstp) */ time64_t delta = iap->ia_atime.tv_sec - ktime_get_real_seconds(); - nfserr = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP); - if (nfserr) - goto done; + resp->status = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP); + if (resp->status != nfs_ok) + return resp->status; if (delta < 0) delta = -delta; @@ -110,9 +100,13 @@ nfsd_proc_setattr(struct svc_rqst *rqstp) } } - nfserr = nfsd_setattr(rqstp, fhp, iap, 0, (time64_t)0); -done: - return nfsd_return_attrs(nfserr, resp); + resp->status = nfsd_setattr(rqstp, fhp, iap, 0, (time64_t)0); + if (resp->status != nfs_ok) + goto out; + + resp->status = fh_getattr(&resp->fh, &resp->stat); +out: + return resp->status; } /* Obsolete, replaced by MNTPROC_MNT. */ @@ -133,17 +127,20 @@ nfsd_proc_lookup(struct svc_rqst *rqstp) { struct nfsd_diropargs *argp = rqstp->rq_argp; struct nfsd_diropres *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: LOOKUP %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); fh_init(&resp->fh, NFS_FHSIZE); - nfserr = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len, - &resp->fh); - + resp->status = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len, + &resp->fh); fh_put(&argp->fh); - return nfsd_return_dirop(nfserr, resp); + if (resp->status != nfs_ok) + goto out; + + resp->status = fh_getattr(&resp->fh, &resp->stat); +out: + return resp->status; } /* @@ -154,16 +151,15 @@ nfsd_proc_readlink(struct svc_rqst *rqstp) { struct nfsd_readlinkargs *argp = rqstp->rq_argp; struct nfsd_readlinkres *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh)); /* Read the symlink. */ resp->len = NFS_MAXPATHLEN; - nfserr = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len); + resp->status = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len); fh_put(&argp->fh); - return nfserr; + return resp->status; } /* @@ -175,7 +171,6 @@ nfsd_proc_read(struct svc_rqst *rqstp) { struct nfsd_readargs *argp = rqstp->rq_argp; struct nfsd_readres *resp = rqstp->rq_resp; - __be32 nfserr; u32 eof; dprintk("nfsd: READ %s %d bytes at %d\n", @@ -197,14 +192,17 @@ nfsd_proc_read(struct svc_rqst *rqstp) svc_reserve_auth(rqstp, (19<<2) + argp->count + 4); resp->count = argp->count; - nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), - argp->offset, - rqstp->rq_vec, argp->vlen, - &resp->count, - &eof); - - if (nfserr) return nfserr; - return fh_getattr(&resp->fh, &resp->stat); + resp->status = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), + argp->offset, + rqstp->rq_vec, argp->vlen, + &resp->count, + &eof); + if (resp->status != nfs_ok) + goto out; + + resp->status = fh_getattr(&resp->fh, &resp->stat); +out: + return resp->status; } /* Reserved */ @@ -223,7 +221,6 @@ nfsd_proc_write(struct svc_rqst *rqstp) { struct nfsd_writeargs *argp = rqstp->rq_argp; struct nfsd_attrstat *resp = rqstp->rq_resp; - __be32 nfserr; unsigned long cnt = argp->len; unsigned int nvecs; @@ -233,12 +230,20 @@ nfsd_proc_write(struct svc_rqst *rqstp) nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages, &argp->first, cnt); - if (!nvecs) - return nfserr_io; - nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), - argp->offset, rqstp->rq_vec, nvecs, - &cnt, NFS_DATA_SYNC, NULL); - return nfsd_return_attrs(nfserr, resp); + if (!nvecs) { + resp->status = nfserr_io; + goto out; + } + + resp->status = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), + argp->offset, rqstp->rq_vec, nvecs, + &cnt, NFS_DATA_SYNC, NULL); + if (resp->status != nfs_ok) + goto out; + + resp->status = fh_getattr(&resp->fh, &resp->stat); +out: + return resp->status; } /* @@ -258,7 +263,6 @@ nfsd_proc_create(struct svc_rqst *rqstp) struct inode *inode; struct dentry *dchild; int type, mode; - __be32 nfserr; int hosterr; dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size); @@ -266,40 +270,40 @@ nfsd_proc_create(struct svc_rqst *rqstp) SVCFH_fmt(dirfhp), argp->len, argp->name); /* First verify the parent file handle */ - nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC); - if (nfserr) + resp->status = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC); + if (resp->status != nfs_ok) goto done; /* must fh_put dirfhp even on error */ /* Check for NFSD_MAY_WRITE in nfsd_create if necessary */ - nfserr = nfserr_exist; + resp->status = nfserr_exist; if (isdotent(argp->name, argp->len)) goto done; hosterr = fh_want_write(dirfhp); if (hosterr) { - nfserr = nfserrno(hosterr); + resp->status = nfserrno(hosterr); goto done; } fh_lock_nested(dirfhp, I_MUTEX_PARENT); dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len); if (IS_ERR(dchild)) { - nfserr = nfserrno(PTR_ERR(dchild)); + resp->status = nfserrno(PTR_ERR(dchild)); goto out_unlock; } fh_init(newfhp, NFS_FHSIZE); - nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp); - if (!nfserr && d_really_is_negative(dchild)) - nfserr = nfserr_noent; + resp->status = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp); + if (!resp->status && d_really_is_negative(dchild)) + resp->status = nfserr_noent; dput(dchild); - if (nfserr) { - if (nfserr != nfserr_noent) + if (resp->status) { + if (resp->status != nfserr_noent) goto out_unlock; /* * If the new file handle wasn't verified, we can't tell * whether the file exists or not. Time to bail ... */ - nfserr = nfserr_acces; + resp->status = nfserr_acces; if (!newfhp->fh_dentry) { printk(KERN_WARNING "nfsd_proc_create: file handle not verified\n"); @@ -332,11 +336,11 @@ nfsd_proc_create(struct svc_rqst *rqstp) * echo thing > device-special-file-or-pipe * by doing a CREATE with type==0 */ - nfserr = nfsd_permission(rqstp, + resp->status = nfsd_permission(rqstp, newfhp->fh_export, newfhp->fh_dentry, NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS); - if (nfserr && nfserr != nfserr_rofs) + if (resp->status && resp->status != nfserr_rofs) goto out_unlock; } } else @@ -372,16 +376,17 @@ nfsd_proc_create(struct svc_rqst *rqstp) attr->ia_valid &= ~ATTR_SIZE; /* Make sure the type and device matches */ - nfserr = nfserr_exist; + resp->status = nfserr_exist; if (inode && type != (inode->i_mode & S_IFMT)) goto out_unlock; } - nfserr = 0; + resp->status = nfs_ok; if (!inode) { /* File doesn't exist. Create it and set attrs */ - nfserr = nfsd_create_locked(rqstp, dirfhp, argp->name, - argp->len, attr, type, rdev, newfhp); + resp->status = nfsd_create_locked(rqstp, dirfhp, argp->name, + argp->len, attr, type, rdev, + newfhp); } else if (type == S_IFREG) { dprintk("nfsd: existing %s, valid=%x, size=%ld\n", argp->name, attr->ia_valid, (long) attr->ia_size); @@ -391,7 +396,8 @@ nfsd_proc_create(struct svc_rqst *rqstp) */ attr->ia_valid &= ATTR_SIZE; if (attr->ia_valid) - nfserr = nfsd_setattr(rqstp, newfhp, attr, 0, (time64_t)0); + resp->status = nfsd_setattr(rqstp, newfhp, attr, 0, + (time64_t)0); } out_unlock: @@ -400,7 +406,11 @@ out_unlock: fh_drop_write(dirfhp); done: fh_put(dirfhp); - return nfsd_return_dirop(nfserr, resp); + if (resp->status != nfs_ok) + goto out; + resp->status = fh_getattr(&resp->fh, &resp->stat); +out: + return resp->status; } static __be32 @@ -463,14 +473,18 @@ nfsd_proc_symlink(struct svc_rqst *rqstp) struct svc_fh newfh; __be32 nfserr; - if (argp->tlen > NFS_MAXPATHLEN) - return nfserr_nametoolong; + if (argp->tlen > NFS_MAXPATHLEN) { + nfserr = nfserr_nametoolong; + goto out; + } argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first, page_address(rqstp->rq_arg.pages[0]), argp->tlen); - if (IS_ERR(argp->tname)) - return nfserrno(PTR_ERR(argp->tname)); + if (IS_ERR(argp->tname)) { + nfserr = nfserrno(PTR_ERR(argp->tname)); + goto out; + } dprintk("nfsd: SYMLINK %s %.*s -> %.*s\n", SVCFH_fmt(&argp->ffh), argp->flen, argp->fname, @@ -483,6 +497,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp) kfree(argp->tname); fh_put(&argp->ffh); fh_put(&newfh); +out: return nfserr; } @@ -495,7 +510,6 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp) { struct nfsd_createargs *argp = rqstp->rq_argp; struct nfsd_diropres *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); @@ -506,10 +520,15 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp) argp->attrs.ia_valid &= ~ATTR_SIZE; fh_init(&resp->fh, NFS_FHSIZE); - nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len, - &argp->attrs, S_IFDIR, 0, &resp->fh); + resp->status = nfsd_create(rqstp, &argp->fh, argp->name, argp->len, + &argp->attrs, S_IFDIR, 0, &resp->fh); fh_put(&argp->fh); - return nfsd_return_dirop(nfserr, resp); + if (resp->status != nfs_ok) + goto out; + + resp->status = fh_getattr(&resp->fh, &resp->stat); +out: + return resp->status; } /* @@ -537,7 +556,6 @@ nfsd_proc_readdir(struct svc_rqst *rqstp) struct nfsd_readdirargs *argp = rqstp->rq_argp; struct nfsd_readdirres *resp = rqstp->rq_resp; int count; - __be32 nfserr; loff_t offset; dprintk("nfsd: READDIR %s %d bytes at %d\n", @@ -558,15 +576,15 @@ nfsd_proc_readdir(struct svc_rqst *rqstp) resp->common.err = nfs_ok; /* Read directory and encode entries on the fly */ offset = argp->cookie; - nfserr = nfsd_readdir(rqstp, &argp->fh, &offset, - &resp->common, nfssvc_encode_entry); + resp->status = nfsd_readdir(rqstp, &argp->fh, &offset, + &resp->common, nfssvc_encode_entry); resp->count = resp->buffer - argp->buffer; if (resp->offset) *resp->offset = htonl(offset); fh_put(&argp->fh); - return nfserr; + return resp->status; } /* @@ -577,14 +595,13 @@ nfsd_proc_statfs(struct svc_rqst *rqstp) { struct nfsd_fhandle *argp = rqstp->rq_argp; struct nfsd_statfsres *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh)); - nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, - NFSD_MAY_BYPASS_GSS_ON_ROOT); + resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats, + NFSD_MAY_BYPASS_GSS_ON_ROOT); fh_put(&argp->fh); - return nfserr; + return resp->status; } /* diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index e793344227c9..4aa8db879ca2 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -1056,12 +1056,8 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) if (rqstp->rq_proc != 0) *nfserrp++ = nfserr; - /* - * For NFSv2, additional info is never returned in case of an error. - */ - if (!(nfserr && rqstp->rq_vers == 2)) - if (!proc->pc_encode(rqstp, nfserrp)) - goto out_encode_err; + if (!proc->pc_encode(rqstp, nfserrp)) + goto out_encode_err; nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1); out_cached_reply: diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 39c004ec7d85..952e71c95d4e 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -434,6 +434,9 @@ nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p) { struct nfsd_attrstat *resp = rqstp->rq_resp; + if (resp->status != nfs_ok) + return xdr_ressize_check(rqstp, p); + p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); return xdr_ressize_check(rqstp, p); } @@ -443,6 +446,9 @@ nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd_diropres *resp = rqstp->rq_resp; + if (resp->status != nfs_ok) + return xdr_ressize_check(rqstp, p); + p = encode_fh(p, &resp->fh); p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); return xdr_ressize_check(rqstp, p); @@ -453,6 +459,9 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd_readlinkres *resp = rqstp->rq_resp; + if (resp->status != nfs_ok) + return xdr_ressize_check(rqstp, p); + *p++ = htonl(resp->len); xdr_ressize_check(rqstp, p); rqstp->rq_res.page_len = resp->len; @@ -470,6 +479,9 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd_readres *resp = rqstp->rq_resp; + if (resp->status != nfs_ok) + return xdr_ressize_check(rqstp, p); + p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); *p++ = htonl(resp->count); xdr_ressize_check(rqstp, p); @@ -490,6 +502,9 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd_readdirres *resp = rqstp->rq_resp; + if (resp->status != nfs_ok) + return xdr_ressize_check(rqstp, p); + xdr_ressize_check(rqstp, p); p = resp->buffer; *p++ = 0; /* no more entries */ @@ -505,6 +520,9 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p) struct nfsd_statfsres *resp = rqstp->rq_resp; struct kstatfs *stat = &resp->stats; + if (resp->status != nfs_ok) + return xdr_ressize_check(rqstp, p); + *p++ = htonl(NFSSVC_MAXBLKSIZE_V2); /* max transfer size */ *p++ = htonl(stat->f_bsize); *p++ = htonl(stat->f_blocks); diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h index 3d3e16d48268..17221931815f 100644 --- a/fs/nfsd/xdr.h +++ b/fs/nfsd/xdr.h @@ -83,26 +83,32 @@ struct nfsd_readdirargs { }; struct nfsd_attrstat { + __be32 status; struct svc_fh fh; struct kstat stat; }; struct nfsd_diropres { + __be32 status; struct svc_fh fh; struct kstat stat; }; struct nfsd_readlinkres { + __be32 status; int len; }; struct nfsd_readres { + __be32 status; struct svc_fh fh; unsigned long count; struct kstat stat; }; struct nfsd_readdirres { + __be32 status; + int count; struct readdir_cd common; @@ -112,6 +118,7 @@ struct nfsd_readdirres { }; struct nfsd_statfsres { + __be32 status; struct kstatfs stats; }; -- cgit From 14168d678a0fa0645609417ad9c384a7c6f895fd Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 1 Oct 2020 18:59:54 -0400 Subject: NFSD: Remove the RETURN_STATUS() macro Refactor: I'm about to change the return value from .pc_func. Clear the way by replacing the RETURN_STATUS() macro with logic that plants the status code directly into the response structure. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs3acl.c | 33 ++++---- fs/nfsd/nfs3proc.c | 235 ++++++++++++++++++++++++++--------------------------- 2 files changed, 130 insertions(+), 138 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index 614168675c17..3fee24dee98c 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -13,8 +13,6 @@ #include "xdr3.h" #include "vfs.h" -#define RETURN_STATUS(st) { resp->status = (st); return (st); } - /* * NULL call. */ @@ -34,17 +32,18 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst *rqstp) struct posix_acl *acl; struct inode *inode; svc_fh *fh; - __be32 nfserr = 0; fh = fh_copy(&resp->fh, &argp->fh); - nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); - if (nfserr) - RETURN_STATUS(nfserr); + resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP); + if (resp->status != nfs_ok) + goto out; inode = d_inode(fh->fh_dentry); - if (argp->mask & ~NFS_ACL_MASK) - RETURN_STATUS(nfserr_inval); + if (argp->mask & ~NFS_ACL_MASK) { + resp->status = nfserr_inval; + goto out; + } resp->mask = argp->mask; if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { @@ -54,7 +53,7 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst *rqstp) acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL); } if (IS_ERR(acl)) { - nfserr = nfserrno(PTR_ERR(acl)); + resp->status = nfserrno(PTR_ERR(acl)); goto fail; } resp->acl_access = acl; @@ -64,19 +63,20 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst *rqstp) of a non-directory! */ acl = get_acl(inode, ACL_TYPE_DEFAULT); if (IS_ERR(acl)) { - nfserr = nfserrno(PTR_ERR(acl)); + resp->status = nfserrno(PTR_ERR(acl)); goto fail; } resp->acl_default = acl; } /* resp->acl_{access,default} are released in nfs3svc_release_getacl. */ - RETURN_STATUS(0); +out: + return resp->status; fail: posix_acl_release(resp->acl_access); posix_acl_release(resp->acl_default); - RETURN_STATUS(nfserr); + goto out; } /* @@ -88,12 +88,11 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp) struct nfsd3_attrstat *resp = rqstp->rq_resp; struct inode *inode; svc_fh *fh; - __be32 nfserr = 0; int error; fh = fh_copy(&resp->fh, &argp->fh); - nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); - if (nfserr) + resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR); + if (resp->status != nfs_ok) goto out; inode = d_inode(fh->fh_dentry); @@ -113,13 +112,13 @@ out_drop_lock: fh_unlock(fh); fh_drop_write(fh); out_errno: - nfserr = nfserrno(error); + resp->status = nfserrno(error); out: /* argp->acl_{access,default} may have been allocated in nfs3svc_decode_setaclargs. */ posix_acl_release(argp->acl_access); posix_acl_release(argp->acl_default); - RETURN_STATUS(nfserr); + return resp->status; } /* diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 3d09959c7042..1d2c149e5ff4 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -15,8 +15,6 @@ #define NFSDDBG_FACILITY NFSDDBG_PROC -#define RETURN_STATUS(st) { resp->status = (st); return (st); } - static int nfs3_ftypes[] = { 0, /* NF3NON */ S_IFREG, /* NF3REG */ @@ -45,20 +43,19 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp) { struct nfsd_fhandle *argp = rqstp->rq_argp; struct nfsd3_attrstat *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: GETATTR(3) %s\n", SVCFH_fmt(&argp->fh)); fh_copy(&resp->fh, &argp->fh); - nfserr = fh_verify(rqstp, &resp->fh, 0, - NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT); - if (nfserr) - RETURN_STATUS(nfserr); - - nfserr = fh_getattr(&resp->fh, &resp->stat); - - RETURN_STATUS(nfserr); + resp->status = fh_verify(rqstp, &resp->fh, 0, + NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT); + if (resp->status != nfs_ok) + goto out; + + resp->status = fh_getattr(&resp->fh, &resp->stat); +out: + return resp->status; } /* @@ -69,15 +66,14 @@ nfsd3_proc_setattr(struct svc_rqst *rqstp) { struct nfsd3_sattrargs *argp = rqstp->rq_argp; struct nfsd3_attrstat *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: SETATTR(3) %s\n", SVCFH_fmt(&argp->fh)); fh_copy(&resp->fh, &argp->fh); - nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs, - argp->check_guard, argp->guardtime); - RETURN_STATUS(nfserr); + resp->status = nfsd_setattr(rqstp, &resp->fh, &argp->attrs, + argp->check_guard, argp->guardtime); + return resp->status; } /* @@ -88,7 +84,6 @@ nfsd3_proc_lookup(struct svc_rqst *rqstp) { struct nfsd3_diropargs *argp = rqstp->rq_argp; struct nfsd3_diropres *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: LOOKUP(3) %s %.*s\n", SVCFH_fmt(&argp->fh), @@ -98,11 +93,10 @@ nfsd3_proc_lookup(struct svc_rqst *rqstp) fh_copy(&resp->dirfh, &argp->fh); fh_init(&resp->fh, NFS3_FHSIZE); - nfserr = nfsd_lookup(rqstp, &resp->dirfh, - argp->name, - argp->len, - &resp->fh); - RETURN_STATUS(nfserr); + resp->status = nfsd_lookup(rqstp, &resp->dirfh, + argp->name, argp->len, + &resp->fh); + return resp->status; } /* @@ -113,7 +107,6 @@ nfsd3_proc_access(struct svc_rqst *rqstp) { struct nfsd3_accessargs *argp = rqstp->rq_argp; struct nfsd3_accessres *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: ACCESS(3) %s 0x%x\n", SVCFH_fmt(&argp->fh), @@ -121,8 +114,8 @@ nfsd3_proc_access(struct svc_rqst *rqstp) fh_copy(&resp->fh, &argp->fh); resp->access = argp->access; - nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL); - RETURN_STATUS(nfserr); + resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL); + return resp->status; } /* @@ -133,15 +126,14 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp) { struct nfsd3_readlinkargs *argp = rqstp->rq_argp; struct nfsd3_readlinkres *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh)); /* Read the symlink. */ fh_copy(&resp->fh, &argp->fh); resp->len = NFS3_MAXPATHLEN; - nfserr = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len); - RETURN_STATUS(nfserr); + resp->status = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len); + return resp->status; } /* @@ -152,7 +144,6 @@ nfsd3_proc_read(struct svc_rqst *rqstp) { struct nfsd3_readargs *argp = rqstp->rq_argp; struct nfsd3_readres *resp = rqstp->rq_resp; - __be32 nfserr; u32 max_blocksize = svc_max_payload(rqstp); unsigned long cnt = min(argp->count, max_blocksize); @@ -169,12 +160,10 @@ nfsd3_proc_read(struct svc_rqst *rqstp) svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4); fh_copy(&resp->fh, &argp->fh); - nfserr = nfsd_read(rqstp, &resp->fh, - argp->offset, - rqstp->rq_vec, argp->vlen, - &resp->count, - &resp->eof); - RETURN_STATUS(nfserr); + resp->status = nfsd_read(rqstp, &resp->fh, argp->offset, + rqstp->rq_vec, argp->vlen, &resp->count, + &resp->eof); + return resp->status; } /* @@ -185,7 +174,6 @@ nfsd3_proc_write(struct svc_rqst *rqstp) { struct nfsd3_writeargs *argp = rqstp->rq_argp; struct nfsd3_writeres *resp = rqstp->rq_resp; - __be32 nfserr; unsigned long cnt = argp->len; unsigned int nvecs; @@ -199,13 +187,16 @@ nfsd3_proc_write(struct svc_rqst *rqstp) resp->committed = argp->stable; nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages, &argp->first, cnt); - if (!nvecs) - RETURN_STATUS(nfserr_io); - nfserr = nfsd_write(rqstp, &resp->fh, argp->offset, - rqstp->rq_vec, nvecs, &cnt, - resp->committed, resp->verf); + if (!nvecs) { + resp->status = nfserr_io; + goto out; + } + resp->status = nfsd_write(rqstp, &resp->fh, argp->offset, + rqstp->rq_vec, nvecs, &cnt, + resp->committed, resp->verf); resp->count = cnt; - RETURN_STATUS(nfserr); +out: + return resp->status; } /* @@ -220,7 +211,6 @@ nfsd3_proc_create(struct svc_rqst *rqstp) struct nfsd3_diropres *resp = rqstp->rq_resp; svc_fh *dirfhp, *newfhp = NULL; struct iattr *attr; - __be32 nfserr; dprintk("nfsd: CREATE(3) %s %.*s\n", SVCFH_fmt(&argp->fh), @@ -241,11 +231,10 @@ nfsd3_proc_create(struct svc_rqst *rqstp) } /* Now create the file and set attributes */ - nfserr = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len, - attr, newfhp, - argp->createmode, (u32 *)argp->verf, NULL, NULL); - - RETURN_STATUS(nfserr); + resp->status = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len, + attr, newfhp, argp->createmode, + (u32 *)argp->verf, NULL, NULL); + return resp->status; } /* @@ -256,7 +245,6 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp) { struct nfsd3_createargs *argp = rqstp->rq_argp; struct nfsd3_diropres *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: MKDIR(3) %s %.*s\n", SVCFH_fmt(&argp->fh), @@ -266,10 +254,10 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp) argp->attrs.ia_valid &= ~ATTR_SIZE; fh_copy(&resp->dirfh, &argp->fh); fh_init(&resp->fh, NFS3_FHSIZE); - nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, - &argp->attrs, S_IFDIR, 0, &resp->fh); + resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, + &argp->attrs, S_IFDIR, 0, &resp->fh); fh_unlock(&resp->dirfh); - RETURN_STATUS(nfserr); + return resp->status; } static __be32 @@ -277,18 +265,23 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp) { struct nfsd3_symlinkargs *argp = rqstp->rq_argp; struct nfsd3_diropres *resp = rqstp->rq_resp; - __be32 nfserr; - if (argp->tlen == 0) - RETURN_STATUS(nfserr_inval); - if (argp->tlen > NFS3_MAXPATHLEN) - RETURN_STATUS(nfserr_nametoolong); + if (argp->tlen == 0) { + resp->status = nfserr_inval; + goto out; + } + if (argp->tlen > NFS3_MAXPATHLEN) { + resp->status = nfserr_nametoolong; + goto out; + } argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first, page_address(rqstp->rq_arg.pages[0]), argp->tlen); - if (IS_ERR(argp->tname)) - RETURN_STATUS(nfserrno(PTR_ERR(argp->tname))); + if (IS_ERR(argp->tname)) { + resp->status = nfserrno(PTR_ERR(argp->tname)); + goto out; + } dprintk("nfsd: SYMLINK(3) %s %.*s -> %.*s\n", SVCFH_fmt(&argp->ffh), @@ -297,10 +290,11 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp) fh_copy(&resp->dirfh, &argp->ffh); fh_init(&resp->fh, NFS3_FHSIZE); - nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen, - argp->tname, &resp->fh); + resp->status = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, + argp->flen, argp->tname, &resp->fh); kfree(argp->tname); - RETURN_STATUS(nfserr); +out: + return resp->status; } /* @@ -311,7 +305,6 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp) { struct nfsd3_mknodargs *argp = rqstp->rq_argp; struct nfsd3_diropres *resp = rqstp->rq_resp; - __be32 nfserr; int type; dev_t rdev = 0; @@ -323,22 +316,28 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp) fh_copy(&resp->dirfh, &argp->fh); fh_init(&resp->fh, NFS3_FHSIZE); - if (argp->ftype == 0 || argp->ftype >= NF3BAD) - RETURN_STATUS(nfserr_inval); + if (argp->ftype == 0 || argp->ftype >= NF3BAD) { + resp->status = nfserr_inval; + goto out; + } if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) { rdev = MKDEV(argp->major, argp->minor); if (MAJOR(rdev) != argp->major || - MINOR(rdev) != argp->minor) - RETURN_STATUS(nfserr_inval); - } else - if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO) - RETURN_STATUS(nfserr_inval); + MINOR(rdev) != argp->minor) { + resp->status = nfserr_inval; + goto out; + } + } else if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO) { + resp->status = nfserr_inval; + goto out; + } type = nfs3_ftypes[argp->ftype]; - nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, - &argp->attrs, type, rdev, &resp->fh); + resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, + &argp->attrs, type, rdev, &resp->fh); fh_unlock(&resp->dirfh); - RETURN_STATUS(nfserr); +out: + return resp->status; } /* @@ -349,7 +348,6 @@ nfsd3_proc_remove(struct svc_rqst *rqstp) { struct nfsd3_diropargs *argp = rqstp->rq_argp; struct nfsd3_attrstat *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: REMOVE(3) %s %.*s\n", SVCFH_fmt(&argp->fh), @@ -358,9 +356,10 @@ nfsd3_proc_remove(struct svc_rqst *rqstp) /* Unlink. -S_IFDIR means file must not be a directory */ fh_copy(&resp->fh, &argp->fh); - nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len); + resp->status = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, + argp->name, argp->len); fh_unlock(&resp->fh); - RETURN_STATUS(nfserr); + return resp->status; } /* @@ -371,7 +370,6 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp) { struct nfsd3_diropargs *argp = rqstp->rq_argp; struct nfsd3_attrstat *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: RMDIR(3) %s %.*s\n", SVCFH_fmt(&argp->fh), @@ -379,9 +377,10 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp) argp->name); fh_copy(&resp->fh, &argp->fh); - nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len); + resp->status = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, + argp->name, argp->len); fh_unlock(&resp->fh); - RETURN_STATUS(nfserr); + return resp->status; } static __be32 @@ -389,7 +388,6 @@ nfsd3_proc_rename(struct svc_rqst *rqstp) { struct nfsd3_renameargs *argp = rqstp->rq_argp; struct nfsd3_renameres *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: RENAME(3) %s %.*s ->\n", SVCFH_fmt(&argp->ffh), @@ -402,9 +400,9 @@ nfsd3_proc_rename(struct svc_rqst *rqstp) fh_copy(&resp->ffh, &argp->ffh); fh_copy(&resp->tfh, &argp->tfh); - nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen, - &resp->tfh, argp->tname, argp->tlen); - RETURN_STATUS(nfserr); + resp->status = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen, + &resp->tfh, argp->tname, argp->tlen); + return resp->status; } static __be32 @@ -412,7 +410,6 @@ nfsd3_proc_link(struct svc_rqst *rqstp) { struct nfsd3_linkargs *argp = rqstp->rq_argp; struct nfsd3_linkres *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: LINK(3) %s ->\n", SVCFH_fmt(&argp->ffh)); @@ -423,9 +420,9 @@ nfsd3_proc_link(struct svc_rqst *rqstp) fh_copy(&resp->fh, &argp->ffh); fh_copy(&resp->tfh, &argp->tfh); - nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen, - &resp->fh); - RETURN_STATUS(nfserr); + resp->status = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen, + &resp->fh); + return resp->status; } /* @@ -436,7 +433,6 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) { struct nfsd3_readdirargs *argp = rqstp->rq_argp; struct nfsd3_readdirres *resp = rqstp->rq_resp; - __be32 nfserr; int count = 0; struct page **p; caddr_t page_addr = NULL; @@ -456,8 +452,8 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) resp->common.err = nfs_ok; resp->buffer = argp->buffer; resp->rqstp = rqstp; - nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie, - &resp->common, nfs3svc_encode_entry); + resp->status = nfsd_readdir(rqstp, &resp->fh, (loff_t *)&argp->cookie, + &resp->common, nfs3svc_encode_entry); memcpy(resp->verf, argp->verf, 8); count = 0; for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) { @@ -485,7 +481,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) resp->offset = NULL; } - RETURN_STATUS(nfserr); + return resp->status; } /* @@ -497,7 +493,6 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp) { struct nfsd3_readdirargs *argp = rqstp->rq_argp; struct nfsd3_readdirres *resp = rqstp->rq_resp; - __be32 nfserr; int count = 0; loff_t offset; struct page **p; @@ -520,17 +515,17 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp) resp->rqstp = rqstp; offset = argp->cookie; - nfserr = fh_verify(rqstp, &resp->fh, S_IFDIR, NFSD_MAY_NOP); - if (nfserr) - RETURN_STATUS(nfserr); + resp->status = fh_verify(rqstp, &resp->fh, S_IFDIR, NFSD_MAY_NOP); + if (resp->status != nfs_ok) + goto out; - if (resp->fh.fh_export->ex_flags & NFSEXP_NOREADDIRPLUS) - RETURN_STATUS(nfserr_notsupp); + if (resp->fh.fh_export->ex_flags & NFSEXP_NOREADDIRPLUS) { + resp->status = nfserr_notsupp; + goto out; + } - nfserr = nfsd_readdir(rqstp, &resp->fh, - &offset, - &resp->common, - nfs3svc_encode_entry_plus); + resp->status = nfsd_readdir(rqstp, &resp->fh, &offset, + &resp->common, nfs3svc_encode_entry_plus); memcpy(resp->verf, argp->verf, 8); for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) { page_addr = page_address(*p); @@ -555,7 +550,8 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp) resp->offset = NULL; } - RETURN_STATUS(nfserr); +out: + return resp->status; } /* @@ -566,14 +562,13 @@ nfsd3_proc_fsstat(struct svc_rqst *rqstp) { struct nfsd_fhandle *argp = rqstp->rq_argp; struct nfsd3_fsstatres *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: FSSTAT(3) %s\n", SVCFH_fmt(&argp->fh)); - nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0); + resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0); fh_put(&argp->fh); - RETURN_STATUS(nfserr); + return resp->status; } /* @@ -584,7 +579,6 @@ nfsd3_proc_fsinfo(struct svc_rqst *rqstp) { struct nfsd_fhandle *argp = rqstp->rq_argp; struct nfsd3_fsinfores *resp = rqstp->rq_resp; - __be32 nfserr; u32 max_blocksize = svc_max_payload(rqstp); dprintk("nfsd: FSINFO(3) %s\n", @@ -600,13 +594,13 @@ nfsd3_proc_fsinfo(struct svc_rqst *rqstp) resp->f_maxfilesize = ~(u32) 0; resp->f_properties = NFS3_FSF_DEFAULT; - nfserr = fh_verify(rqstp, &argp->fh, 0, - NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT); + resp->status = fh_verify(rqstp, &argp->fh, 0, + NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT); /* Check special features of the file system. May request * different read/write sizes for file systems known to have * problems with large blocks */ - if (nfserr == 0) { + if (resp->status == nfs_ok) { struct super_block *sb = argp->fh.fh_dentry->d_sb; /* Note that we don't care for remote fs's here */ @@ -617,7 +611,7 @@ nfsd3_proc_fsinfo(struct svc_rqst *rqstp) } fh_put(&argp->fh); - RETURN_STATUS(nfserr); + return resp->status; } /* @@ -628,7 +622,6 @@ nfsd3_proc_pathconf(struct svc_rqst *rqstp) { struct nfsd_fhandle *argp = rqstp->rq_argp; struct nfsd3_pathconfres *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: PATHCONF(3) %s\n", SVCFH_fmt(&argp->fh)); @@ -641,9 +634,9 @@ nfsd3_proc_pathconf(struct svc_rqst *rqstp) resp->p_case_insensitive = 0; resp->p_case_preserving = 1; - nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP); + resp->status = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP); - if (nfserr == 0) { + if (resp->status == nfs_ok) { struct super_block *sb = argp->fh.fh_dentry->d_sb; /* Note that we don't care for remote fs's here */ @@ -660,10 +653,9 @@ nfsd3_proc_pathconf(struct svc_rqst *rqstp) } fh_put(&argp->fh); - RETURN_STATUS(nfserr); + return resp->status; } - /* * Commit a file (range) to stable storage. */ @@ -672,21 +664,22 @@ nfsd3_proc_commit(struct svc_rqst *rqstp) { struct nfsd3_commitargs *argp = rqstp->rq_argp; struct nfsd3_commitres *resp = rqstp->rq_resp; - __be32 nfserr; dprintk("nfsd: COMMIT(3) %s %u@%Lu\n", SVCFH_fmt(&argp->fh), argp->count, (unsigned long long) argp->offset); - if (argp->offset > NFS_OFFSET_MAX) - RETURN_STATUS(nfserr_inval); + if (argp->offset > NFS_OFFSET_MAX) { + resp->status = nfserr_inval; + goto out; + } fh_copy(&resp->fh, &argp->fh); - nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count, - resp->verf); - - RETURN_STATUS(nfserr); + resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset, + argp->count, resp->verf); +out: + return resp->status; } -- cgit From 4b74fd793a77f6149d68dbf95574311af9506e39 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 1 Oct 2020 19:00:00 -0400 Subject: NFSD: Map nfserr_wrongsec outside of nfsd_dispatch Refactor: Handle this NFS version-specific mapping in the only place where nfserr_wrongsec is generated. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/export.c | 2 +- fs/nfsd/nfssvc.c | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index cb777fe82988..21e404e7cb68 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -1002,7 +1002,7 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp) if (nfsd4_spo_must_allow(rqstp)) return 0; - return nfserr_wrongsec; + return rqstp->rq_vers < 4 ? nfserr_acces : nfserr_wrongsec; } /* diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 4aa8db879ca2..beb3875241cb 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -964,8 +964,6 @@ static __be32 map_new_errors(u32 vers, __be32 nfserr) { if (nfserr == nfserr_jukebox && vers == 2) return nfserr_dropit; - if (nfserr == nfserr_wrongsec && vers < 4) - return nfserr_acces; return nfserr; } -- cgit From cc028a10a48c3c555d7772d02f56eea9f86fdf79 Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Fri, 2 Oct 2020 15:52:44 -0400 Subject: NFSD: Hoist status code encoding into XDR encoder functions The original intent was presumably to reduce code duplication. The trade-off was: - No support for an NFSD proc function returning a non-success RPC accept_stat value. - No support for void NFS replies to non-NULL procedures. - Everyone pays for the deduplication with a few extra conditional branches in a hot path. In addition, nfsd_dispatch() leaves *statp uninitialized in the success path, unlike svc_generic_dispatch(). Address all of these problems by moving the logic for encoding the NFS status code into the NFS XDR encoders themselves. Then update the NFS .pc_func methods to return an RPC accept_stat value. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs2acl.c | 19 +++++---- fs/nfsd/nfs3acl.c | 9 +++-- fs/nfsd/nfs3proc.c | 44 ++++++++++----------- fs/nfsd/nfs3xdr.c | 19 +++++++-- fs/nfsd/nfs4proc.c | 7 ++-- fs/nfsd/nfs4xdr.c | 5 +-- fs/nfsd/nfsproc.c | 113 +++++++++++++++++++++++++++-------------------------- fs/nfsd/nfssvc.c | 21 +++------- fs/nfsd/nfsxdr.c | 23 +++++++++-- fs/nfsd/xdr.h | 5 +++ 10 files changed, 145 insertions(+), 120 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 6f46afdb0616..6a900f770dd2 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -21,7 +21,7 @@ static __be32 nfsacld_proc_null(struct svc_rqst *rqstp) { - return nfs_ok; + return rpc_success; } /* @@ -79,7 +79,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp) /* resp->acl_{access,default} are released in nfssvc_release_getacl. */ out: - return resp->status; + return rpc_success; fail: posix_acl_release(resp->acl_access); @@ -131,7 +131,7 @@ out: nfssvc_decode_setaclargs. */ posix_acl_release(argp->acl_access); posix_acl_release(argp->acl_default); - return resp->status; + return rpc_success; out_drop_lock: fh_unlock(fh); @@ -157,7 +157,7 @@ static __be32 nfsacld_proc_getattr(struct svc_rqst *rqstp) goto out; resp->status = fh_getattr(&resp->fh, &resp->stat); out: - return resp->status; + return rpc_success; } /* @@ -179,7 +179,7 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp) goto out; resp->status = fh_getattr(&resp->fh, &resp->stat); out: - return resp->status; + return rpc_success; } /* @@ -275,6 +275,7 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) int n; int w; + *p++ = resp->status; if (resp->status != nfs_ok) return xdr_ressize_check(rqstp, p); @@ -317,10 +318,12 @@ static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd_attrstat *resp = rqstp->rq_resp; + *p++ = resp->status; if (resp->status != nfs_ok) - return xdr_ressize_check(rqstp, p); + goto out; p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat); +out: return xdr_ressize_check(rqstp, p); } @@ -329,11 +332,13 @@ static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_accessres *resp = rqstp->rq_resp; + *p++ = resp->status; if (resp->status != nfs_ok) - return xdr_ressize_check(rqstp, p); + goto out; p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat); *p++ = htonl(resp->access); +out: return xdr_ressize_check(rqstp, p); } diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index 3fee24dee98c..34a394e50e1d 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -19,7 +19,7 @@ static __be32 nfsd3_proc_null(struct svc_rqst *rqstp) { - return nfs_ok; + return rpc_success; } /* @@ -71,7 +71,7 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst *rqstp) /* resp->acl_{access,default} are released in nfs3svc_release_getacl. */ out: - return resp->status; + return rpc_success; fail: posix_acl_release(resp->acl_access); @@ -118,7 +118,7 @@ out: nfs3svc_decode_setaclargs. */ posix_acl_release(argp->acl_access); posix_acl_release(argp->acl_default); - return resp->status; + return rpc_success; } /* @@ -173,6 +173,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p) struct nfsd3_getaclres *resp = rqstp->rq_resp; struct dentry *dentry = resp->fh.fh_dentry; + *p++ = resp->status; p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); if (resp->status == 0 && dentry && d_really_is_positive(dentry)) { struct inode *inode = d_inode(dentry); @@ -217,8 +218,8 @@ static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_attrstat *resp = rqstp->rq_resp; + *p++ = resp->status; p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh); - return xdr_ressize_check(rqstp, p); } diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 1d2c149e5ff4..14468613d150 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -32,7 +32,7 @@ static int nfs3_ftypes[] = { static __be32 nfsd3_proc_null(struct svc_rqst *rqstp) { - return nfs_ok; + return rpc_success; } /* @@ -55,7 +55,7 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp) resp->status = fh_getattr(&resp->fh, &resp->stat); out: - return resp->status; + return rpc_success; } /* @@ -73,7 +73,7 @@ nfsd3_proc_setattr(struct svc_rqst *rqstp) fh_copy(&resp->fh, &argp->fh); resp->status = nfsd_setattr(rqstp, &resp->fh, &argp->attrs, argp->check_guard, argp->guardtime); - return resp->status; + return rpc_success; } /* @@ -96,7 +96,7 @@ nfsd3_proc_lookup(struct svc_rqst *rqstp) resp->status = nfsd_lookup(rqstp, &resp->dirfh, argp->name, argp->len, &resp->fh); - return resp->status; + return rpc_success; } /* @@ -115,7 +115,7 @@ nfsd3_proc_access(struct svc_rqst *rqstp) fh_copy(&resp->fh, &argp->fh); resp->access = argp->access; resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL); - return resp->status; + return rpc_success; } /* @@ -133,7 +133,7 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp) fh_copy(&resp->fh, &argp->fh); resp->len = NFS3_MAXPATHLEN; resp->status = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len); - return resp->status; + return rpc_success; } /* @@ -163,7 +163,7 @@ nfsd3_proc_read(struct svc_rqst *rqstp) resp->status = nfsd_read(rqstp, &resp->fh, argp->offset, rqstp->rq_vec, argp->vlen, &resp->count, &resp->eof); - return resp->status; + return rpc_success; } /* @@ -196,7 +196,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp) resp->committed, resp->verf); resp->count = cnt; out: - return resp->status; + return rpc_success; } /* @@ -234,7 +234,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp) resp->status = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len, attr, newfhp, argp->createmode, (u32 *)argp->verf, NULL, NULL); - return resp->status; + return rpc_success; } /* @@ -257,7 +257,7 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp) resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len, &argp->attrs, S_IFDIR, 0, &resp->fh); fh_unlock(&resp->dirfh); - return resp->status; + return rpc_success; } static __be32 @@ -294,7 +294,7 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp) argp->flen, argp->tname, &resp->fh); kfree(argp->tname); out: - return resp->status; + return rpc_success; } /* @@ -337,7 +337,7 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp) &argp->attrs, type, rdev, &resp->fh); fh_unlock(&resp->dirfh); out: - return resp->status; + return rpc_success; } /* @@ -359,7 +359,7 @@ nfsd3_proc_remove(struct svc_rqst *rqstp) resp->status = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len); fh_unlock(&resp->fh); - return resp->status; + return rpc_success; } /* @@ -380,7 +380,7 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp) resp->status = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len); fh_unlock(&resp->fh); - return resp->status; + return rpc_success; } static __be32 @@ -402,7 +402,7 @@ nfsd3_proc_rename(struct svc_rqst *rqstp) fh_copy(&resp->tfh, &argp->tfh); resp->status = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen, &resp->tfh, argp->tname, argp->tlen); - return resp->status; + return rpc_success; } static __be32 @@ -422,7 +422,7 @@ nfsd3_proc_link(struct svc_rqst *rqstp) fh_copy(&resp->tfh, &argp->tfh); resp->status = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen, &resp->fh); - return resp->status; + return rpc_success; } /* @@ -481,7 +481,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp) resp->offset = NULL; } - return resp->status; + return rpc_success; } /* @@ -551,7 +551,7 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp) } out: - return resp->status; + return rpc_success; } /* @@ -568,7 +568,7 @@ nfsd3_proc_fsstat(struct svc_rqst *rqstp) resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0); fh_put(&argp->fh); - return resp->status; + return rpc_success; } /* @@ -611,7 +611,7 @@ nfsd3_proc_fsinfo(struct svc_rqst *rqstp) } fh_put(&argp->fh); - return resp->status; + return rpc_success; } /* @@ -653,7 +653,7 @@ nfsd3_proc_pathconf(struct svc_rqst *rqstp) } fh_put(&argp->fh); - return resp->status; + return rpc_success; } /* @@ -679,7 +679,7 @@ nfsd3_proc_commit(struct svc_rqst *rqstp) resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count, resp->verf); out: - return resp->status; + return rpc_success; } diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c index e540fd1a29d8..9c23b6acf234 100644 --- a/fs/nfsd/nfs3xdr.c +++ b/fs/nfsd/nfs3xdr.c @@ -641,10 +641,7 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p) /* * XDR encode functions */ -/* - * There must be an encoding function for void results so svc_process - * will work properly. - */ + int nfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p) { @@ -657,6 +654,7 @@ nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_attrstat *resp = rqstp->rq_resp; + *p++ = resp->status; if (resp->status == 0) { lease_get_mtime(d_inode(resp->fh.fh_dentry), &resp->stat.mtime); @@ -671,6 +669,7 @@ nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_attrstat *resp = rqstp->rq_resp; + *p++ = resp->status; p = encode_wcc_data(rqstp, p, &resp->fh); return xdr_ressize_check(rqstp, p); } @@ -681,6 +680,7 @@ nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_diropres *resp = rqstp->rq_resp; + *p++ = resp->status; if (resp->status == 0) { p = encode_fh(p, &resp->fh); p = encode_post_op_attr(rqstp, p, &resp->fh); @@ -695,6 +695,7 @@ nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_accessres *resp = rqstp->rq_resp; + *p++ = resp->status; p = encode_post_op_attr(rqstp, p, &resp->fh); if (resp->status == 0) *p++ = htonl(resp->access); @@ -707,6 +708,7 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_readlinkres *resp = rqstp->rq_resp; + *p++ = resp->status; p = encode_post_op_attr(rqstp, p, &resp->fh); if (resp->status == 0) { *p++ = htonl(resp->len); @@ -729,6 +731,7 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_readres *resp = rqstp->rq_resp; + *p++ = resp->status; p = encode_post_op_attr(rqstp, p, &resp->fh); if (resp->status == 0) { *p++ = htonl(resp->count); @@ -754,6 +757,7 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_writeres *resp = rqstp->rq_resp; + *p++ = resp->status; p = encode_wcc_data(rqstp, p, &resp->fh); if (resp->status == 0) { *p++ = htonl(resp->count); @@ -770,6 +774,7 @@ nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_diropres *resp = rqstp->rq_resp; + *p++ = resp->status; if (resp->status == 0) { *p++ = xdr_one; p = encode_fh(p, &resp->fh); @@ -785,6 +790,7 @@ nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_renameres *resp = rqstp->rq_resp; + *p++ = resp->status; p = encode_wcc_data(rqstp, p, &resp->ffh); p = encode_wcc_data(rqstp, p, &resp->tfh); return xdr_ressize_check(rqstp, p); @@ -796,6 +802,7 @@ nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_linkres *resp = rqstp->rq_resp; + *p++ = resp->status; p = encode_post_op_attr(rqstp, p, &resp->fh); p = encode_wcc_data(rqstp, p, &resp->tfh); return xdr_ressize_check(rqstp, p); @@ -807,6 +814,7 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_readdirres *resp = rqstp->rq_resp; + *p++ = resp->status; p = encode_post_op_attr(rqstp, p, &resp->fh); if (resp->status == 0) { @@ -1059,6 +1067,7 @@ nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p) struct kstatfs *s = &resp->stats; u64 bs = s->f_bsize; + *p++ = resp->status; *p++ = xdr_zero; /* no post_op_attr */ if (resp->status == 0) { @@ -1079,6 +1088,7 @@ nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_fsinfores *resp = rqstp->rq_resp; + *p++ = resp->status; *p++ = xdr_zero; /* no post_op_attr */ if (resp->status == 0) { @@ -1124,6 +1134,7 @@ nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd3_commitres *resp = rqstp->rq_resp; + *p++ = resp->status; p = encode_wcc_data(rqstp, p, &resp->fh); /* Write verifier */ if (resp->status == 0) { diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 578fc9f4e3d1..b09334414b98 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -2165,7 +2165,7 @@ nfsd4_removexattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, static __be32 nfsd4_proc_null(struct svc_rqst *rqstp) { - return nfs_ok; + return rpc_success; } static inline void nfsd4_increment_op_stats(u32 opnum) @@ -2457,15 +2457,14 @@ encode_op: nfsd4_increment_op_stats(op->opnum); } - cstate->status = status; fh_put(current_fh); fh_put(save_fh); BUG_ON(cstate->replay_owner); out: + cstate->status = status; /* Reset deferral mechanism for RPC deferrals */ set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags); - dprintk("nfsv4 compound returned %d\n", ntohl(status)); - return status; + return rpc_success; } #define op_encode_hdr_size (2) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index c28d908d7a15..a37828c375ae 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -5167,15 +5167,14 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p) int nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p) { - /* - * All that remains is to write the tag and operation count... - */ struct nfsd4_compoundres *resp = rqstp->rq_resp; struct xdr_buf *buf = resp->xdr.buf; WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len + buf->tail[0].iov_len); + *p = resp->cstate.status; + rqstp->rq_next_page = resp->xdr.page_ptr + 1; p = resp->tagp; diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 526170319ecf..0d71549f9d42 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -16,7 +16,7 @@ static __be32 nfsd_proc_null(struct svc_rqst *rqstp) { - return nfs_ok; + return rpc_success; } /* @@ -38,7 +38,7 @@ nfsd_proc_getattr(struct svc_rqst *rqstp) goto out; resp->status = fh_getattr(&resp->fh, &resp->stat); out: - return resp->status; + return rpc_success; } /* @@ -85,7 +85,7 @@ nfsd_proc_setattr(struct svc_rqst *rqstp) resp->status = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP); if (resp->status != nfs_ok) - return resp->status; + goto out; if (delta < 0) delta = -delta; @@ -106,14 +106,14 @@ nfsd_proc_setattr(struct svc_rqst *rqstp) resp->status = fh_getattr(&resp->fh, &resp->stat); out: - return resp->status; + return rpc_success; } /* Obsolete, replaced by MNTPROC_MNT. */ static __be32 nfsd_proc_root(struct svc_rqst *rqstp) { - return nfs_ok; + return rpc_success; } /* @@ -140,7 +140,7 @@ nfsd_proc_lookup(struct svc_rqst *rqstp) resp->status = fh_getattr(&resp->fh, &resp->stat); out: - return resp->status; + return rpc_success; } /* @@ -159,7 +159,7 @@ nfsd_proc_readlink(struct svc_rqst *rqstp) resp->status = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len); fh_put(&argp->fh); - return resp->status; + return rpc_success; } /* @@ -197,19 +197,18 @@ nfsd_proc_read(struct svc_rqst *rqstp) rqstp->rq_vec, argp->vlen, &resp->count, &eof); - if (resp->status != nfs_ok) - goto out; - - resp->status = fh_getattr(&resp->fh, &resp->stat); -out: - return resp->status; + if (resp->status == nfs_ok) + resp->status = fh_getattr(&resp->fh, &resp->stat); + else if (resp->status == nfserr_jukebox) + return rpc_drop_reply; + return rpc_success; } /* Reserved */ static __be32 nfsd_proc_writecache(struct svc_rqst *rqstp) { - return nfs_ok; + return rpc_success; } /* @@ -238,12 +237,12 @@ nfsd_proc_write(struct svc_rqst *rqstp) resp->status = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), argp->offset, rqstp->rq_vec, nvecs, &cnt, NFS_DATA_SYNC, NULL); - if (resp->status != nfs_ok) - goto out; - - resp->status = fh_getattr(&resp->fh, &resp->stat); + if (resp->status == nfs_ok) + resp->status = fh_getattr(&resp->fh, &resp->stat); + else if (resp->status == nfserr_jukebox) + return rpc_drop_reply; out: - return resp->status; + return rpc_success; } /* @@ -410,47 +409,48 @@ done: goto out; resp->status = fh_getattr(&resp->fh, &resp->stat); out: - return resp->status; + return rpc_success; } static __be32 nfsd_proc_remove(struct svc_rqst *rqstp) { struct nfsd_diropargs *argp = rqstp->rq_argp; - __be32 nfserr; + struct nfsd_stat *resp = rqstp->rq_resp; dprintk("nfsd: REMOVE %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); /* Unlink. -SIFDIR means file must not be a directory */ - nfserr = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, argp->name, argp->len); + resp->status = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, + argp->name, argp->len); fh_put(&argp->fh); - return nfserr; + return rpc_success; } static __be32 nfsd_proc_rename(struct svc_rqst *rqstp) { struct nfsd_renameargs *argp = rqstp->rq_argp; - __be32 nfserr; + struct nfsd_stat *resp = rqstp->rq_resp; dprintk("nfsd: RENAME %s %.*s -> \n", SVCFH_fmt(&argp->ffh), argp->flen, argp->fname); dprintk("nfsd: -> %s %.*s\n", SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname); - nfserr = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen, - &argp->tfh, argp->tname, argp->tlen); + resp->status = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen, + &argp->tfh, argp->tname, argp->tlen); fh_put(&argp->ffh); fh_put(&argp->tfh); - return nfserr; + return rpc_success; } static __be32 nfsd_proc_link(struct svc_rqst *rqstp) { struct nfsd_linkargs *argp = rqstp->rq_argp; - __be32 nfserr; + struct nfsd_stat *resp = rqstp->rq_resp; dprintk("nfsd: LINK %s ->\n", SVCFH_fmt(&argp->ffh)); @@ -459,22 +459,22 @@ nfsd_proc_link(struct svc_rqst *rqstp) argp->tlen, argp->tname); - nfserr = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen, - &argp->ffh); + resp->status = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen, + &argp->ffh); fh_put(&argp->ffh); fh_put(&argp->tfh); - return nfserr; + return rpc_success; } static __be32 nfsd_proc_symlink(struct svc_rqst *rqstp) { struct nfsd_symlinkargs *argp = rqstp->rq_argp; + struct nfsd_stat *resp = rqstp->rq_resp; struct svc_fh newfh; - __be32 nfserr; if (argp->tlen > NFS_MAXPATHLEN) { - nfserr = nfserr_nametoolong; + resp->status = nfserr_nametoolong; goto out; } @@ -482,7 +482,7 @@ nfsd_proc_symlink(struct svc_rqst *rqstp) page_address(rqstp->rq_arg.pages[0]), argp->tlen); if (IS_ERR(argp->tname)) { - nfserr = nfserrno(PTR_ERR(argp->tname)); + resp->status = nfserrno(PTR_ERR(argp->tname)); goto out; } @@ -491,14 +491,14 @@ nfsd_proc_symlink(struct svc_rqst *rqstp) argp->tlen, argp->tname); fh_init(&newfh, NFS_FHSIZE); - nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen, - argp->tname, &newfh); + resp->status = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen, + argp->tname, &newfh); kfree(argp->tname); fh_put(&argp->ffh); fh_put(&newfh); out: - return nfserr; + return rpc_success; } /* @@ -528,7 +528,7 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp) resp->status = fh_getattr(&resp->fh, &resp->stat); out: - return resp->status; + return rpc_success; } /* @@ -538,13 +538,14 @@ static __be32 nfsd_proc_rmdir(struct svc_rqst *rqstp) { struct nfsd_diropargs *argp = rqstp->rq_argp; - __be32 nfserr; + struct nfsd_stat *resp = rqstp->rq_resp; dprintk("nfsd: RMDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name); - nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len); + resp->status = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, + argp->name, argp->len); fh_put(&argp->fh); - return nfserr; + return rpc_success; } /* @@ -584,7 +585,7 @@ nfsd_proc_readdir(struct svc_rqst *rqstp) *resp->offset = htonl(offset); fh_put(&argp->fh); - return resp->status; + return rpc_success; } /* @@ -601,7 +602,7 @@ nfsd_proc_statfs(struct svc_rqst *rqstp) resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats, NFSD_MAY_BYPASS_GSS_ON_ROOT); fh_put(&argp->fh); - return resp->status; + return rpc_success; } /* @@ -622,7 +623,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { .pc_argsize = sizeof(struct nfsd_void), .pc_ressize = sizeof(struct nfsd_void), .pc_cachetype = RC_NOCACHE, - .pc_xdrressize = ST, + .pc_xdrressize = 0, }, [NFSPROC_GETATTR] = { .pc_func = nfsd_proc_getattr, @@ -651,7 +652,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { .pc_argsize = sizeof(struct nfsd_void), .pc_ressize = sizeof(struct nfsd_void), .pc_cachetype = RC_NOCACHE, - .pc_xdrressize = ST, + .pc_xdrressize = 0, }, [NFSPROC_LOOKUP] = { .pc_func = nfsd_proc_lookup, @@ -689,7 +690,7 @@ static const struct svc_procedure nfsd_procedures2[18] = { .pc_argsize = sizeof(struct nfsd_void), .pc_ressize = sizeof(struct nfsd_void), .pc_cachetype = RC_NOCACHE, - .pc_xdrressize = ST, + .pc_xdrressize = 0, }, [NFSPROC_WRITE] = { .pc_func = nfsd_proc_write, @@ -714,36 +715,36 @@ static const struct svc_procedure nfsd_procedures2[18] = { [NFSPROC_REMOVE] = { .pc_func = nfsd_proc_remove, .pc_decode = nfssvc_decode_diropargs, - .pc_encode = nfssvc_encode_void, + .pc_encode = nfssvc_encode_stat, .pc_argsize = sizeof(struct nfsd_diropargs), - .pc_ressize = sizeof(struct nfsd_void), + .pc_ressize = sizeof(struct nfsd_stat), .pc_cachetype = RC_REPLSTAT, .pc_xdrressize = ST, }, [NFSPROC_RENAME] = { .pc_func = nfsd_proc_rename, .pc_decode = nfssvc_decode_renameargs, - .pc_encode = nfssvc_encode_void, + .pc_encode = nfssvc_encode_stat, .pc_argsize = sizeof(struct nfsd_renameargs), - .pc_ressize = sizeof(struct nfsd_void), + .pc_ressize = sizeof(struct nfsd_stat), .pc_cachetype = RC_REPLSTAT, .pc_xdrressize = ST, }, [NFSPROC_LINK] = { .pc_func = nfsd_proc_link, .pc_decode = nfssvc_decode_linkargs, - .pc_encode = nfssvc_encode_void, + .pc_encode = nfssvc_encode_stat, .pc_argsize = sizeof(struct nfsd_linkargs), - .pc_ressize = sizeof(struct nfsd_void), + .pc_ressize = sizeof(struct nfsd_stat), .pc_cachetype = RC_REPLSTAT, .pc_xdrressize = ST, }, [NFSPROC_SYMLINK] = { .pc_func = nfsd_proc_symlink, .pc_decode = nfssvc_decode_symlinkargs, - .pc_encode = nfssvc_encode_void, + .pc_encode = nfssvc_encode_stat, .pc_argsize = sizeof(struct nfsd_symlinkargs), - .pc_ressize = sizeof(struct nfsd_void), + .pc_ressize = sizeof(struct nfsd_stat), .pc_cachetype = RC_REPLSTAT, .pc_xdrressize = ST, }, @@ -760,9 +761,9 @@ static const struct svc_procedure nfsd_procedures2[18] = { [NFSPROC_RMDIR] = { .pc_func = nfsd_proc_rmdir, .pc_decode = nfssvc_decode_diropargs, - .pc_encode = nfssvc_encode_void, + .pc_encode = nfssvc_encode_stat, .pc_argsize = sizeof(struct nfsd_diropargs), - .pc_ressize = sizeof(struct nfsd_void), + .pc_ressize = sizeof(struct nfsd_stat), .pc_cachetype = RC_REPLSTAT, .pc_xdrressize = ST, }, diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index beb3875241cb..27b1ad136150 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -960,13 +960,6 @@ out: return 0; } -static __be32 map_new_errors(u32 vers, __be32 nfserr) -{ - if (nfserr == nfserr_jukebox && vers == 2) - return nfserr_dropit; - return nfserr; -} - /* * A write procedure can have a large argument, and a read procedure can * have a large reply, but no NFSv2 or NFSv3 procedure has argument and @@ -1014,7 +1007,7 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) const struct svc_procedure *proc = rqstp->rq_procinfo; struct kvec *argv = &rqstp->rq_arg.head[0]; struct kvec *resv = &rqstp->rq_res.head[0]; - __be32 nfserr, *nfserrp; + __be32 *p; dprintk("nfsd_dispatch: vers %d proc %d\n", rqstp->rq_vers, rqstp->rq_proc); @@ -1043,18 +1036,14 @@ int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp) * Need to grab the location to store the status, as * NFSv4 does some encoding while processing */ - nfserrp = resv->iov_base + resv->iov_len; + p = resv->iov_base + resv->iov_len; resv->iov_len += sizeof(__be32); - nfserr = proc->pc_func(rqstp); - nfserr = map_new_errors(rqstp->rq_vers, nfserr); - if (nfserr == nfserr_dropit || test_bit(RQ_DROPME, &rqstp->rq_flags)) + *statp = proc->pc_func(rqstp); + if (*statp == rpc_drop_reply || test_bit(RQ_DROPME, &rqstp->rq_flags)) goto out_update_drop; - if (rqstp->rq_proc != 0) - *nfserrp++ = nfserr; - - if (!proc->pc_encode(rqstp, nfserrp)) + if (!proc->pc_encode(rqstp, p)) goto out_encode_err; nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1); diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c index 952e71c95d4e..8a288c8fcd57 100644 --- a/fs/nfsd/nfsxdr.c +++ b/fs/nfsd/nfsxdr.c @@ -429,15 +429,25 @@ nfssvc_encode_void(struct svc_rqst *rqstp, __be32 *p) return xdr_ressize_check(rqstp, p); } +int +nfssvc_encode_stat(struct svc_rqst *rqstp, __be32 *p) +{ + struct nfsd_stat *resp = rqstp->rq_resp; + + *p++ = resp->status; + return xdr_ressize_check(rqstp, p); +} + int nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p) { struct nfsd_attrstat *resp = rqstp->rq_resp; + *p++ = resp->status; if (resp->status != nfs_ok) - return xdr_ressize_check(rqstp, p); - + goto out; p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); +out: return xdr_ressize_check(rqstp, p); } @@ -446,11 +456,12 @@ nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd_diropres *resp = rqstp->rq_resp; + *p++ = resp->status; if (resp->status != nfs_ok) - return xdr_ressize_check(rqstp, p); - + goto out; p = encode_fh(p, &resp->fh); p = encode_fattr(rqstp, p, &resp->fh, &resp->stat); +out: return xdr_ressize_check(rqstp, p); } @@ -459,6 +470,7 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd_readlinkres *resp = rqstp->rq_resp; + *p++ = resp->status; if (resp->status != nfs_ok) return xdr_ressize_check(rqstp, p); @@ -479,6 +491,7 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd_readres *resp = rqstp->rq_resp; + *p++ = resp->status; if (resp->status != nfs_ok) return xdr_ressize_check(rqstp, p); @@ -502,6 +515,7 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p) { struct nfsd_readdirres *resp = rqstp->rq_resp; + *p++ = resp->status; if (resp->status != nfs_ok) return xdr_ressize_check(rqstp, p); @@ -520,6 +534,7 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p) struct nfsd_statfsres *resp = rqstp->rq_resp; struct kstatfs *stat = &resp->stats; + *p++ = resp->status; if (resp->status != nfs_ok) return xdr_ressize_check(rqstp, p); diff --git a/fs/nfsd/xdr.h b/fs/nfsd/xdr.h index 17221931815f..0ff336b0b25f 100644 --- a/fs/nfsd/xdr.h +++ b/fs/nfsd/xdr.h @@ -82,6 +82,10 @@ struct nfsd_readdirargs { __be32 * buffer; }; +struct nfsd_stat { + __be32 status; +}; + struct nfsd_attrstat { __be32 status; struct svc_fh fh; @@ -153,6 +157,7 @@ int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *); int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *); int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *); int nfssvc_encode_void(struct svc_rqst *, __be32 *); +int nfssvc_encode_stat(struct svc_rqst *, __be32 *); int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *); int nfssvc_encode_diropres(struct svc_rqst *, __be32 *); int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *); -- cgit From 528b84934eb904ecafea4ed482a1c52e3c814050 Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Mon, 28 Sep 2020 13:08:58 -0400 Subject: NFSD: Add READ_PLUS data support This patch adds READ_PLUS support for returning a single NFS4_CONTENT_DATA segment to the client. This is basically the same as the READ operation, only with the extra information about data segments. Signed-off-by: Anna Schumaker Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4proc.c | 21 +++++++++++++ fs/nfsd/nfs4xdr.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 105 insertions(+), 3 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index b09334414b98..3dd69b6315c8 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -2590,6 +2590,20 @@ static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) return (op_encode_hdr_size + 2 + XDR_QUADLEN(rlen)) * sizeof(__be32); } +static inline u32 nfsd4_read_plus_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) +{ + u32 maxcount = svc_max_payload(rqstp); + u32 rlen = min(op->u.read.rd_length, maxcount); + /* + * If we detect that the file changed during hole encoding, then we + * recover by encoding the remaining reply as data. This means we need + * to set aside enough room to encode two data segments. + */ + u32 seg_len = 2 * (1 + 2 + 1); + + return (op_encode_hdr_size + 2 + seg_len + XDR_QUADLEN(rlen)) * sizeof(__be32); +} + static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op) { u32 maxcount = 0, rlen = 0; @@ -3162,6 +3176,13 @@ static const struct nfsd4_operation nfsd4_ops[] = { .op_name = "OP_COPY", .op_rsize_bop = nfsd4_copy_rsize, }, + [OP_READ_PLUS] = { + .op_func = nfsd4_read, + .op_release = nfsd4_read_release, + .op_name = "OP_READ_PLUS", + .op_rsize_bop = nfsd4_read_plus_rsize, + .op_get_currentstateid = nfsd4_get_readstateid, + }, [OP_SEEK] = { .op_func = nfsd4_seek, .op_name = "OP_SEEK", diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index a37828c375ae..206670a20290 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2173,7 +2173,7 @@ static const nfsd4_dec nfsd4_dec_ops[] = { [OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_OFFLOAD_CANCEL] = (nfsd4_dec)nfsd4_decode_offload_status, [OP_OFFLOAD_STATUS] = (nfsd4_dec)nfsd4_decode_offload_status, - [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_notsupp, + [OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_read, [OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek, [OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp, [OP_CLONE] = (nfsd4_dec)nfsd4_decode_clone, @@ -2261,7 +2261,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) */ cachethis |= nfsd4_cache_this_op(op); - if (op->opnum == OP_READ) { + if (op->opnum == OP_READ || op->opnum == OP_READ_PLUS) { readcount++; readbytes += nfsd4_max_reply(argp->rqstp, op); } else @@ -4597,6 +4597,87 @@ nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr, return nfserr_resource; p = xdr_encode_hyper(p, os->count); *p++ = cpu_to_be32(0); + return nfserr; +} + +static __be32 +nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, + struct nfsd4_read *read, + unsigned long maxcount, u32 *eof) +{ + struct xdr_stream *xdr = &resp->xdr; + struct file *file = read->rd_nf->nf_file; + int starting_len = xdr->buf->len; + __be32 nfserr; + __be32 *p, tmp; + __be64 tmp64; + + maxcount = min_t(unsigned long, maxcount, (xdr->buf->buflen - xdr->buf->len)); + + /* Content type, offset, byte count */ + p = xdr_reserve_space(xdr, 4 + 8 + 4); + if (!p) + return nfserr_resource; + + read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, maxcount); + if (read->rd_vlen < 0) + return nfserr_resource; + + nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset, + resp->rqstp->rq_vec, read->rd_vlen, &maxcount, eof); + if (nfserr) + return nfserr; + + tmp = htonl(NFS4_CONTENT_DATA); + write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4); + tmp64 = cpu_to_be64(read->rd_offset); + write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp64, 8); + tmp = htonl(maxcount); + write_bytes_to_xdr_buf(xdr->buf, starting_len + 12, &tmp, 4); + return nfs_ok; +} + +static __be32 +nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, + struct nfsd4_read *read) +{ + unsigned long maxcount; + struct xdr_stream *xdr = &resp->xdr; + struct file *file; + int starting_len = xdr->buf->len; + int segments = 0; + __be32 *p, tmp; + u32 eof; + + if (nfserr) + return nfserr; + file = read->rd_nf->nf_file; + + /* eof flag, segment count */ + p = xdr_reserve_space(xdr, 4 + 4); + if (!p) + return nfserr_resource; + xdr_commit_encode(xdr); + + maxcount = svc_max_payload(resp->rqstp); + maxcount = min_t(unsigned long, maxcount, + (xdr->buf->buflen - xdr->buf->len)); + maxcount = min_t(unsigned long, maxcount, read->rd_length); + + eof = read->rd_offset >= i_size_read(file_inode(file)); + if (!eof) { + nfserr = nfsd4_encode_read_plus_data(resp, read, maxcount, &eof); + segments++; + } + + if (nfserr) + xdr_truncate_encode(xdr, starting_len); + else { + tmp = htonl(eof); + write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4); + tmp = htonl(segments); + write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4); + } return nfserr; } @@ -4974,7 +5055,7 @@ static const nfsd4_enc nfsd4_enc_ops[] = { [OP_LAYOUTSTATS] = (nfsd4_enc)nfsd4_encode_noop, [OP_OFFLOAD_CANCEL] = (nfsd4_enc)nfsd4_encode_noop, [OP_OFFLOAD_STATUS] = (nfsd4_enc)nfsd4_encode_offload_status, - [OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_noop, + [OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_read_plus, [OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek, [OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop, [OP_CLONE] = (nfsd4_enc)nfsd4_encode_noop, -- cgit From 2db27992dd565bf400658edc18f67aed0b6bc6cb Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Mon, 28 Sep 2020 13:08:59 -0400 Subject: NFSD: Add READ_PLUS hole segment encoding However, we still only reply to the READ_PLUS call with a single segment at this time. Signed-off-by: Anna Schumaker Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 206670a20290..74645c5c44bd 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4608,10 +4608,13 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, struct xdr_stream *xdr = &resp->xdr; struct file *file = read->rd_nf->nf_file; int starting_len = xdr->buf->len; + loff_t hole_pos = vfs_llseek(file, read->rd_offset, SEEK_HOLE); __be32 nfserr; __be32 *p, tmp; __be64 tmp64; + if (hole_pos > read->rd_offset) + maxcount = min_t(unsigned long, maxcount, hole_pos - read->rd_offset); maxcount = min_t(unsigned long, maxcount, (xdr->buf->buflen - xdr->buf->len)); /* Content type, offset, byte count */ @@ -4637,6 +4640,27 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, return nfs_ok; } +static __be32 +nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp, + struct nfsd4_read *read, + unsigned long maxcount, u32 *eof) +{ + struct file *file = read->rd_nf->nf_file; + __be32 *p; + + /* Content type, offset, byte count */ + p = xdr_reserve_space(&resp->xdr, 4 + 8 + 8); + if (!p) + return nfserr_resource; + + *p++ = htonl(NFS4_CONTENT_HOLE); + p = xdr_encode_hyper(p, read->rd_offset); + p = xdr_encode_hyper(p, maxcount); + + *eof = (read->rd_offset + maxcount) >= i_size_read(file_inode(file)); + return nfs_ok; +} + static __be32 nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_read *read) @@ -4647,6 +4671,7 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, int starting_len = xdr->buf->len; int segments = 0; __be32 *p, tmp; + loff_t pos; u32 eof; if (nfserr) @@ -4665,11 +4690,23 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, maxcount = min_t(unsigned long, maxcount, read->rd_length); eof = read->rd_offset >= i_size_read(file_inode(file)); - if (!eof) { + if (eof) + goto out; + + pos = vfs_llseek(file, read->rd_offset, SEEK_DATA); + if (pos == -ENXIO) + pos = i_size_read(file_inode(file)); + + if (pos > read->rd_offset) { + maxcount = pos - read->rd_offset; + nfserr = nfsd4_encode_read_plus_hole(resp, read, maxcount, &eof); + segments++; + } else { nfserr = nfsd4_encode_read_plus_data(resp, read, maxcount, &eof); segments++; } +out: if (nfserr) xdr_truncate_encode(xdr, starting_len); else { -- cgit From 278765ea0752e67922c0f2aaf1138f6ba227688d Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Mon, 28 Sep 2020 13:09:00 -0400 Subject: NFSD: Return both a hole and a data segment But only one of each right now. We'll expand on this in the next patch. Signed-off-by: Anna Schumaker Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 56 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 16 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 74645c5c44bd..2aff50745d6d 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4603,7 +4603,7 @@ nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr, static __be32 nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, struct nfsd4_read *read, - unsigned long maxcount, u32 *eof) + unsigned long *maxcount, u32 *eof) { struct xdr_stream *xdr = &resp->xdr; struct file *file = read->rd_nf->nf_file; @@ -4614,20 +4614,20 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, __be64 tmp64; if (hole_pos > read->rd_offset) - maxcount = min_t(unsigned long, maxcount, hole_pos - read->rd_offset); - maxcount = min_t(unsigned long, maxcount, (xdr->buf->buflen - xdr->buf->len)); + *maxcount = min_t(unsigned long, *maxcount, hole_pos - read->rd_offset); + *maxcount = min_t(unsigned long, *maxcount, (xdr->buf->buflen - xdr->buf->len)); /* Content type, offset, byte count */ p = xdr_reserve_space(xdr, 4 + 8 + 4); if (!p) return nfserr_resource; - read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, maxcount); + read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, *maxcount); if (read->rd_vlen < 0) return nfserr_resource; nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset, - resp->rqstp->rq_vec, read->rd_vlen, &maxcount, eof); + resp->rqstp->rq_vec, read->rd_vlen, maxcount, eof); if (nfserr) return nfserr; @@ -4635,7 +4635,7 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4); tmp64 = cpu_to_be64(read->rd_offset); write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp64, 8); - tmp = htonl(maxcount); + tmp = htonl(*maxcount); write_bytes_to_xdr_buf(xdr->buf, starting_len + 12, &tmp, 4); return nfs_ok; } @@ -4643,11 +4643,19 @@ nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, static __be32 nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp, struct nfsd4_read *read, - unsigned long maxcount, u32 *eof) + unsigned long *maxcount, u32 *eof) { struct file *file = read->rd_nf->nf_file; + loff_t data_pos = vfs_llseek(file, read->rd_offset, SEEK_DATA); + unsigned long count; __be32 *p; + if (data_pos == -ENXIO) + data_pos = i_size_read(file_inode(file)); + else if (data_pos <= read->rd_offset) + return nfserr_resource; + count = data_pos - read->rd_offset; + /* Content type, offset, byte count */ p = xdr_reserve_space(&resp->xdr, 4 + 8 + 8); if (!p) @@ -4655,9 +4663,10 @@ nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp, *p++ = htonl(NFS4_CONTENT_HOLE); p = xdr_encode_hyper(p, read->rd_offset); - p = xdr_encode_hyper(p, maxcount); + p = xdr_encode_hyper(p, count); - *eof = (read->rd_offset + maxcount) >= i_size_read(file_inode(file)); + *eof = (read->rd_offset + count) >= i_size_read(file_inode(file)); + *maxcount = min_t(unsigned long, count, *maxcount); return nfs_ok; } @@ -4665,7 +4674,7 @@ static __be32 nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_read *read) { - unsigned long maxcount; + unsigned long maxcount, count; struct xdr_stream *xdr = &resp->xdr; struct file *file; int starting_len = xdr->buf->len; @@ -4688,6 +4697,7 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, maxcount = min_t(unsigned long, maxcount, (xdr->buf->buflen - xdr->buf->len)); maxcount = min_t(unsigned long, maxcount, read->rd_length); + count = maxcount; eof = read->rd_offset >= i_size_read(file_inode(file)); if (eof) @@ -4696,24 +4706,38 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, pos = vfs_llseek(file, read->rd_offset, SEEK_DATA); if (pos == -ENXIO) pos = i_size_read(file_inode(file)); + else if (pos < 0) + pos = read->rd_offset; - if (pos > read->rd_offset) { - maxcount = pos - read->rd_offset; - nfserr = nfsd4_encode_read_plus_hole(resp, read, maxcount, &eof); + if (pos == read->rd_offset) { + maxcount = count; + nfserr = nfsd4_encode_read_plus_data(resp, read, &maxcount, &eof); + if (nfserr) + goto out; + count -= maxcount; + read->rd_offset += maxcount; segments++; - } else { - nfserr = nfsd4_encode_read_plus_data(resp, read, maxcount, &eof); + } + + if (count > 0 && !eof) { + maxcount = count; + nfserr = nfsd4_encode_read_plus_hole(resp, read, &maxcount, &eof); + if (nfserr) + goto out; + count -= maxcount; + read->rd_offset += maxcount; segments++; } out: - if (nfserr) + if (nfserr && segments == 0) xdr_truncate_encode(xdr, starting_len); else { tmp = htonl(eof); write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4); tmp = htonl(segments); write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4); + nfserr = nfs_ok; } return nfserr; -- cgit From 9f0b5792f07d8f0745c3620d577d6930ff2a96fd Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Mon, 28 Sep 2020 13:09:01 -0400 Subject: NFSD: Encode a full READ_PLUS reply Reply to the client with multiple hole and data segments. I use the result of the first vfs_llseek() call for encoding as an optimization so we don't have to immediately repeat the call. This also lets us encode any remaining reply as data if we get an unexpected result while trying to calculate a hole. Signed-off-by: Anna Schumaker Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 2aff50745d6d..833a2c64dfe8 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -4603,16 +4603,18 @@ nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr, static __be32 nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp, struct nfsd4_read *read, - unsigned long *maxcount, u32 *eof) + unsigned long *maxcount, u32 *eof, + loff_t *pos) { struct xdr_stream *xdr = &resp->xdr; struct file *file = read->rd_nf->nf_file; int starting_len = xdr->buf->len; - loff_t hole_pos = vfs_llseek(file, read->rd_offset, SEEK_HOLE); + loff_t hole_pos; __be32 nfserr; __be32 *p, tmp; __be64 tmp64; + hole_pos = pos ? *pos : vfs_llseek(file, read->rd_offset, SEEK_HOLE); if (hole_pos > read->rd_offset) *maxcount = min_t(unsigned long, *maxcount, hole_pos - read->rd_offset); *maxcount = min_t(unsigned long, *maxcount, (xdr->buf->buflen - xdr->buf->len)); @@ -4647,13 +4649,14 @@ nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp, { struct file *file = read->rd_nf->nf_file; loff_t data_pos = vfs_llseek(file, read->rd_offset, SEEK_DATA); + loff_t f_size = i_size_read(file_inode(file)); unsigned long count; __be32 *p; if (data_pos == -ENXIO) - data_pos = i_size_read(file_inode(file)); - else if (data_pos <= read->rd_offset) - return nfserr_resource; + data_pos = f_size; + else if (data_pos <= read->rd_offset || (data_pos < f_size && data_pos % PAGE_SIZE)) + return nfsd4_encode_read_plus_data(resp, read, maxcount, eof, &f_size); count = data_pos - read->rd_offset; /* Content type, offset, byte count */ @@ -4665,7 +4668,7 @@ nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp, p = xdr_encode_hyper(p, read->rd_offset); p = xdr_encode_hyper(p, count); - *eof = (read->rd_offset + count) >= i_size_read(file_inode(file)); + *eof = (read->rd_offset + count) >= f_size; *maxcount = min_t(unsigned long, count, *maxcount); return nfs_ok; } @@ -4678,8 +4681,10 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, struct xdr_stream *xdr = &resp->xdr; struct file *file; int starting_len = xdr->buf->len; + int last_segment = xdr->buf->len; int segments = 0; __be32 *p, tmp; + bool is_data; loff_t pos; u32 eof; @@ -4703,29 +4708,22 @@ nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr, if (eof) goto out; - pos = vfs_llseek(file, read->rd_offset, SEEK_DATA); - if (pos == -ENXIO) - pos = i_size_read(file_inode(file)); - else if (pos < 0) - pos = read->rd_offset; + pos = vfs_llseek(file, read->rd_offset, SEEK_HOLE); + is_data = pos > read->rd_offset; - if (pos == read->rd_offset) { + while (count > 0 && !eof) { maxcount = count; - nfserr = nfsd4_encode_read_plus_data(resp, read, &maxcount, &eof); - if (nfserr) - goto out; - count -= maxcount; - read->rd_offset += maxcount; - segments++; - } - - if (count > 0 && !eof) { - maxcount = count; - nfserr = nfsd4_encode_read_plus_hole(resp, read, &maxcount, &eof); + if (is_data) + nfserr = nfsd4_encode_read_plus_data(resp, read, &maxcount, &eof, + segments == 0 ? &pos : NULL); + else + nfserr = nfsd4_encode_read_plus_hole(resp, read, &maxcount, &eof); if (nfserr) goto out; count -= maxcount; read->rd_offset += maxcount; + is_data = !is_data; + last_segment = xdr->buf->len; segments++; } @@ -4737,7 +4735,10 @@ out: write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4); tmp = htonl(segments); write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4); - nfserr = nfs_ok; + if (nfserr) { + xdr_truncate_encode(xdr, last_segment); + nfserr = nfs_ok; + } } return nfserr; -- cgit From c1488428a8daf5257a12dcec1739147e6aaf9557 Mon Sep 17 00:00:00 2001 From: Tom Rix Date: Sun, 11 Oct 2020 08:51:55 -0700 Subject: nfsd: remove unneeded break Because every path through nfs4_find_file()'s switch does an explicit return, the break is not needed. Signed-off-by: Tom Rix Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 1 - 1 file changed, 1 deletion(-) (limited to 'fs') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 4f3964582b68..d7f27ed6b794 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -5723,7 +5723,6 @@ nfs4_find_file(struct nfs4_stid *s, int flags) return find_readable_file(s->sc_file); else return find_writeable_file(s->sc_file); - break; } return NULL; -- cgit From 0cfcd405e758ba1d277e58436fb32f06888c3e41 Mon Sep 17 00:00:00 2001 From: Dai Ngo Date: Sun, 18 Oct 2020 23:42:49 -0400 Subject: NFSv4.2: Fix NFS4ERR_STALE error when doing inter server copy NFS_FS=y as dependency of CONFIG_NFSD_V4_2_INTER_SSC still have build errors and some configs with NFSD=m to get NFS4ERR_STALE error when doing inter server copy. Added ops table in nfs_common for knfsd to access NFS client modules. Fixes: 3ac3711adb88 ("NFSD: Fix NFS server build errors") Signed-off-by: Dai Ngo Signed-off-by: J. Bruce Fields --- fs/nfs/nfs4file.c | 38 ++++++++++++++++---- fs/nfs/nfs4super.c | 5 +++ fs/nfs/super.c | 17 +++++++++ fs/nfs_common/Makefile | 1 + fs/nfs_common/nfs_ssc.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/nfsd/Kconfig | 2 +- fs/nfsd/nfs4proc.c | 3 +- 7 files changed, 152 insertions(+), 8 deletions(-) create mode 100644 fs/nfs_common/nfs_ssc.c (limited to 'fs') diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index fdfc77486ace..984938024011 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "delegation.h" #include "internal.h" #include "iostat.h" @@ -314,9 +315,8 @@ out: static int read_name_gen = 1; #define SSC_READ_NAME_BODY "ssc_read_%d" -struct file * -nfs42_ssc_open(struct vfsmount *ss_mnt, struct nfs_fh *src_fh, - nfs4_stateid *stateid) +static struct file *__nfs42_ssc_open(struct vfsmount *ss_mnt, + struct nfs_fh *src_fh, nfs4_stateid *stateid) { struct nfs_fattr fattr; struct file *filep, *res; @@ -398,14 +398,40 @@ out_filep: fput(filep); goto out_free_name; } -EXPORT_SYMBOL_GPL(nfs42_ssc_open); -void nfs42_ssc_close(struct file *filep) + +static void __nfs42_ssc_close(struct file *filep) { struct nfs_open_context *ctx = nfs_file_open_context(filep); ctx->state->flags = 0; } -EXPORT_SYMBOL_GPL(nfs42_ssc_close); + +static const struct nfs4_ssc_client_ops nfs4_ssc_clnt_ops_tbl = { + .sco_open = __nfs42_ssc_open, + .sco_close = __nfs42_ssc_close, +}; + +/** + * nfs42_ssc_register_ops - Wrapper to register NFS_V4 ops in nfs_common + * + * Return values: + * None + */ +void nfs42_ssc_register_ops(void) +{ + nfs42_ssc_register(&nfs4_ssc_clnt_ops_tbl); +} + +/** + * nfs42_ssc_unregister_ops - wrapper to un-register NFS_V4 ops in nfs_common + * + * Return values: + * None. + */ +void nfs42_ssc_unregister_ops(void) +{ + nfs42_ssc_unregister(&nfs4_ssc_clnt_ops_tbl); +} #endif /* CONFIG_NFS_V4_2 */ const struct file_operations nfs4_file_operations = { diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c index 0c1ab846b83d..93f5c1678ec2 100644 --- a/fs/nfs/nfs4super.c +++ b/fs/nfs/nfs4super.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "delegation.h" #include "internal.h" #include "nfs4_fs.h" @@ -279,6 +280,9 @@ static int __init init_nfs_v4(void) if (err) goto out2; +#ifdef CONFIG_NFS_V4_2 + nfs42_ssc_register_ops(); +#endif register_nfs_version(&nfs_v4); return 0; out2: @@ -297,6 +301,7 @@ static void __exit exit_nfs_v4(void) unregister_nfs_version(&nfs_v4); #ifdef CONFIG_NFS_V4_2 nfs4_xattr_cache_exit(); + nfs42_ssc_unregister_ops(); #endif nfs4_unregister_sysctl(); nfs_idmap_quit(); diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 7a70287f21a2..f7dad8227a5f 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -57,6 +57,7 @@ #include #include +#include #include "nfs4_fs.h" #include "callback.h" @@ -85,6 +86,10 @@ const struct super_operations nfs_sops = { }; EXPORT_SYMBOL_GPL(nfs_sops); +static const struct nfs_ssc_client_ops nfs_ssc_clnt_ops_tbl = { + .sco_sb_deactive = nfs_sb_deactive, +}; + #if IS_ENABLED(CONFIG_NFS_V4) static int __init register_nfs4_fs(void) { @@ -106,6 +111,16 @@ static void unregister_nfs4_fs(void) } #endif +static void nfs_ssc_register_ops(void) +{ + nfs_ssc_register(&nfs_ssc_clnt_ops_tbl); +} + +static void nfs_ssc_unregister_ops(void) +{ + nfs_ssc_unregister(&nfs_ssc_clnt_ops_tbl); +} + static struct shrinker acl_shrinker = { .count_objects = nfs_access_cache_count, .scan_objects = nfs_access_cache_scan, @@ -133,6 +148,7 @@ int __init register_nfs_fs(void) ret = register_shrinker(&acl_shrinker); if (ret < 0) goto error_3; + nfs_ssc_register_ops(); return 0; error_3: nfs_unregister_sysctl(); @@ -152,6 +168,7 @@ void __exit unregister_nfs_fs(void) unregister_shrinker(&acl_shrinker); nfs_unregister_sysctl(); unregister_nfs4_fs(); + nfs_ssc_unregister_ops(); unregister_filesystem(&nfs_fs_type); } diff --git a/fs/nfs_common/Makefile b/fs/nfs_common/Makefile index 4bebe834c009..fa82f5aaa6d9 100644 --- a/fs/nfs_common/Makefile +++ b/fs/nfs_common/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_NFS_ACL_SUPPORT) += nfs_acl.o nfs_acl-objs := nfsacl.o obj-$(CONFIG_GRACE_PERIOD) += grace.o +obj-$(CONFIG_GRACE_PERIOD) += nfs_ssc.o diff --git a/fs/nfs_common/nfs_ssc.c b/fs/nfs_common/nfs_ssc.c new file mode 100644 index 000000000000..f43bbb373913 --- /dev/null +++ b/fs/nfs_common/nfs_ssc.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * fs/nfs_common/nfs_ssc_comm.c + * + * Helper for knfsd's SSC to access ops in NFS client modules + * + * Author: Dai Ngo + * + * Copyright (c) 2020, Oracle and/or its affiliates. + */ + +#include +#include +#include +#include "../nfs/nfs4_fs.h" + +MODULE_LICENSE("GPL"); + +struct nfs_ssc_client_ops_tbl nfs_ssc_client_tbl; +EXPORT_SYMBOL_GPL(nfs_ssc_client_tbl); + +#ifdef CONFIG_NFS_V4_2 +/** + * nfs42_ssc_register - install the NFS_V4 client ops in the nfs_ssc_client_tbl + * @ops: NFS_V4 ops to be installed + * + * Return values: + * None + */ +void nfs42_ssc_register(const struct nfs4_ssc_client_ops *ops) +{ + nfs_ssc_client_tbl.ssc_nfs4_ops = ops; +} +EXPORT_SYMBOL_GPL(nfs42_ssc_register); + +/** + * nfs42_ssc_unregister - uninstall the NFS_V4 client ops from + * the nfs_ssc_client_tbl + * @ops: ops to be uninstalled + * + * Return values: + * None + */ +void nfs42_ssc_unregister(const struct nfs4_ssc_client_ops *ops) +{ + if (nfs_ssc_client_tbl.ssc_nfs4_ops != ops) + return; + + nfs_ssc_client_tbl.ssc_nfs4_ops = NULL; +} +EXPORT_SYMBOL_GPL(nfs42_ssc_unregister); +#endif /* CONFIG_NFS_V4_2 */ + +#ifdef CONFIG_NFS_V4_2 +/** + * nfs_ssc_register - install the NFS_FS client ops in the nfs_ssc_client_tbl + * @ops: NFS_FS ops to be installed + * + * Return values: + * None + */ +void nfs_ssc_register(const struct nfs_ssc_client_ops *ops) +{ + nfs_ssc_client_tbl.ssc_nfs_ops = ops; +} +EXPORT_SYMBOL_GPL(nfs_ssc_register); + +/** + * nfs_ssc_unregister - uninstall the NFS_FS client ops from + * the nfs_ssc_client_tbl + * @ops: ops to be uninstalled + * + * Return values: + * None + */ +void nfs_ssc_unregister(const struct nfs_ssc_client_ops *ops) +{ + if (nfs_ssc_client_tbl.ssc_nfs_ops != ops) + return; + nfs_ssc_client_tbl.ssc_nfs_ops = NULL; +} +EXPORT_SYMBOL_GPL(nfs_ssc_unregister); + +#else +void nfs_ssc_register(const struct nfs_ssc_client_ops *ops) +{ +} +EXPORT_SYMBOL_GPL(nfs_ssc_register); + +void nfs_ssc_unregister(const struct nfs_ssc_client_ops *ops) +{ +} +EXPORT_SYMBOL_GPL(nfs_ssc_unregister); +#endif /* CONFIG_NFS_V4_2 */ diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index 9223e13c3051..dbbc583d6273 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig @@ -136,7 +136,7 @@ config NFSD_FLEXFILELAYOUT config NFSD_V4_2_INTER_SSC bool "NFSv4.2 inter server to server COPY" - depends on NFSD_V4 && NFS_V4_1 && NFS_V4_2 && NFS_FS=y + depends on NFSD_V4 && NFS_V4_1 && NFS_V4_2 help This option enables support for NFSv4.2 inter server to server copy where the destination server calls the NFSv4.2 diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 3dd69b6315c8..ad2fa1a8e7ad 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "idmap.h" #include "cache.h" @@ -1247,7 +1248,7 @@ out_err: static void nfsd4_interssc_disconnect(struct vfsmount *ss_mnt) { - nfs_sb_deactive(ss_mnt->mnt_sb); + nfs_do_sb_deactive(ss_mnt->mnt_sb); mntput(ss_mnt); } -- cgit