/* We have an implied reference to net thanks to nfsd_serv_try_get */
        localio = nfs_to->nfsd_open_local_fh(net, uuid->dom, rpc_clnt,
                                             cred, nfs_fh, fmode);
-       if (IS_ERR(localio)) {
-               rcu_read_lock();
-               nfs_to->nfsd_serv_put(net);
-               rcu_read_unlock();
-       }
+       if (IS_ERR(localio))
+               nfs_to_nfsd_net_put(net);
+
        return localio;
 }
 EXPORT_SYMBOL_GPL(nfs_open_local_fh);
 
 }
 
 /**
- * nfsd_file_put_local - put the reference to nfsd_file and local nfsd_serv
- * @nf: nfsd_file of which to put the references
+ * nfsd_file_put_local - put nfsd_file reference and arm nfsd_serv_put in caller
+ * @nf: nfsd_file of which to put the reference
  *
- * First put the reference of the nfsd_file and then put the
- * reference to the associated nn->nfsd_serv.
+ * First save the associated net to return to caller, then put
+ * the reference of the nfsd_file.
  */
-void
-nfsd_file_put_local(struct nfsd_file *nf) __must_hold(rcu)
+struct net *
+nfsd_file_put_local(struct nfsd_file *nf)
 {
        struct net *net = nf->nf_net;
 
        nfsd_file_put(nf);
-       nfsd_serv_put(net);
+       return net;
 }
 
 /**
 
 int nfsd_file_cache_start_net(struct net *net);
 void nfsd_file_cache_shutdown_net(struct net *net);
 void nfsd_file_put(struct nfsd_file *nf);
-void nfsd_file_put_local(struct nfsd_file *nf);
+struct net *nfsd_file_put_local(struct nfsd_file *nf);
 struct nfsd_file *nfsd_file_get(struct nfsd_file *nf);
 struct file *nfsd_file_file(struct nfsd_file *nf);
 void nfsd_file_close_inode_sync(struct inode *inode);
 
                                                const struct cred *,
                                                const struct nfs_fh *,
                                                const fmode_t);
-       void (*nfsd_file_put_local)(struct nfsd_file *);
+       struct net *(*nfsd_file_put_local)(struct nfsd_file *);
        struct file *(*nfsd_file_file)(struct nfsd_file *);
 } ____cacheline_aligned;
 
                   struct rpc_clnt *, const struct cred *,
                   const struct nfs_fh *, const fmode_t);
 
-static inline void nfs_to_nfsd_file_put_local(struct nfsd_file *localio)
+static inline void nfs_to_nfsd_net_put(struct net *net)
 {
        /*
         * Once reference to nfsd_serv is dropped, NFSD could be
         * by always taking RCU.
         */
        rcu_read_lock();
-       nfs_to->nfsd_file_put_local(localio);
+       nfs_to->nfsd_serv_put(net);
        rcu_read_unlock();
 }
 
+static inline void nfs_to_nfsd_file_put_local(struct nfsd_file *localio)
+{
+       /*
+        * Must not hold RCU otherwise nfsd_file_put() can easily trigger:
+        * "Voluntary context switch within RCU read-side critical section!"
+        * by scheduling deep in underlying filesystem (e.g. XFS).
+        */
+       struct net *net = nfs_to->nfsd_file_put_local(localio);
+
+       nfs_to_nfsd_net_put(net);
+}
+
 #else   /* CONFIG_NFS_LOCALIO */
 static inline void nfsd_localio_ops_init(void)
 {