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 <dai.ngo@oracle.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
Dai Ngo 2020-10-18 23:42:49 -04:00 committed by J. Bruce Fields
parent d48c812474
commit 0cfcd405e7
8 changed files with 219 additions and 8 deletions

View File

@ -9,6 +9,7 @@
#include <linux/falloc.h> #include <linux/falloc.h>
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/nfs_ssc.h>
#include "delegation.h" #include "delegation.h"
#include "internal.h" #include "internal.h"
#include "iostat.h" #include "iostat.h"
@ -314,9 +315,8 @@ out:
static int read_name_gen = 1; static int read_name_gen = 1;
#define SSC_READ_NAME_BODY "ssc_read_%d" #define SSC_READ_NAME_BODY "ssc_read_%d"
struct file * static struct file *__nfs42_ssc_open(struct vfsmount *ss_mnt,
nfs42_ssc_open(struct vfsmount *ss_mnt, struct nfs_fh *src_fh, struct nfs_fh *src_fh, nfs4_stateid *stateid)
nfs4_stateid *stateid)
{ {
struct nfs_fattr fattr; struct nfs_fattr fattr;
struct file *filep, *res; struct file *filep, *res;
@ -398,14 +398,40 @@ out_filep:
fput(filep); fput(filep);
goto out_free_name; 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); struct nfs_open_context *ctx = nfs_file_open_context(filep);
ctx->state->flags = 0; 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 */ #endif /* CONFIG_NFS_V4_2 */
const struct file_operations nfs4_file_operations = { const struct file_operations nfs4_file_operations = {

View File

@ -7,6 +7,7 @@
#include <linux/mount.h> #include <linux/mount.h>
#include <linux/nfs4_mount.h> #include <linux/nfs4_mount.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/nfs_ssc.h>
#include "delegation.h" #include "delegation.h"
#include "internal.h" #include "internal.h"
#include "nfs4_fs.h" #include "nfs4_fs.h"
@ -279,6 +280,9 @@ static int __init init_nfs_v4(void)
if (err) if (err)
goto out2; goto out2;
#ifdef CONFIG_NFS_V4_2
nfs42_ssc_register_ops();
#endif
register_nfs_version(&nfs_v4); register_nfs_version(&nfs_v4);
return 0; return 0;
out2: out2:
@ -297,6 +301,7 @@ static void __exit exit_nfs_v4(void)
unregister_nfs_version(&nfs_v4); unregister_nfs_version(&nfs_v4);
#ifdef CONFIG_NFS_V4_2 #ifdef CONFIG_NFS_V4_2
nfs4_xattr_cache_exit(); nfs4_xattr_cache_exit();
nfs42_ssc_unregister_ops();
#endif #endif
nfs4_unregister_sysctl(); nfs4_unregister_sysctl();
nfs_idmap_quit(); nfs_idmap_quit();

View File

@ -57,6 +57,7 @@
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/nfs_ssc.h>
#include "nfs4_fs.h" #include "nfs4_fs.h"
#include "callback.h" #include "callback.h"
@ -85,6 +86,10 @@ const struct super_operations nfs_sops = {
}; };
EXPORT_SYMBOL_GPL(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) #if IS_ENABLED(CONFIG_NFS_V4)
static int __init register_nfs4_fs(void) static int __init register_nfs4_fs(void)
{ {
@ -106,6 +111,16 @@ static void unregister_nfs4_fs(void)
} }
#endif #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 = { static struct shrinker acl_shrinker = {
.count_objects = nfs_access_cache_count, .count_objects = nfs_access_cache_count,
.scan_objects = nfs_access_cache_scan, .scan_objects = nfs_access_cache_scan,
@ -133,6 +148,7 @@ int __init register_nfs_fs(void)
ret = register_shrinker(&acl_shrinker); ret = register_shrinker(&acl_shrinker);
if (ret < 0) if (ret < 0)
goto error_3; goto error_3;
nfs_ssc_register_ops();
return 0; return 0;
error_3: error_3:
nfs_unregister_sysctl(); nfs_unregister_sysctl();
@ -152,6 +168,7 @@ void __exit unregister_nfs_fs(void)
unregister_shrinker(&acl_shrinker); unregister_shrinker(&acl_shrinker);
nfs_unregister_sysctl(); nfs_unregister_sysctl();
unregister_nfs4_fs(); unregister_nfs4_fs();
nfs_ssc_unregister_ops();
unregister_filesystem(&nfs_fs_type); unregister_filesystem(&nfs_fs_type);
} }

View File

@ -7,3 +7,4 @@ obj-$(CONFIG_NFS_ACL_SUPPORT) += nfs_acl.o
nfs_acl-objs := nfsacl.o nfs_acl-objs := nfsacl.o
obj-$(CONFIG_GRACE_PERIOD) += grace.o obj-$(CONFIG_GRACE_PERIOD) += grace.o
obj-$(CONFIG_GRACE_PERIOD) += nfs_ssc.o

94
fs/nfs_common/nfs_ssc.c Normal file
View File

@ -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 <dai.ngo@oracle.com>
*
* Copyright (c) 2020, Oracle and/or its affiliates.
*/
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/nfs_ssc.h>
#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 */

View File

@ -136,7 +136,7 @@ config NFSD_FLEXFILELAYOUT
config NFSD_V4_2_INTER_SSC config NFSD_V4_2_INTER_SSC
bool "NFSv4.2 inter server to server COPY" 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 help
This option enables support for NFSv4.2 inter server to This option enables support for NFSv4.2 inter server to
server copy where the destination server calls the NFSv4.2 server copy where the destination server calls the NFSv4.2

View File

@ -38,6 +38,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/sunrpc/addr.h> #include <linux/sunrpc/addr.h>
#include <linux/nfs_ssc.h>
#include "idmap.h" #include "idmap.h"
#include "cache.h" #include "cache.h"
@ -1247,7 +1248,7 @@ out_err:
static void static void
nfsd4_interssc_disconnect(struct vfsmount *ss_mnt) 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); mntput(ss_mnt);
} }

67
include/linux/nfs_ssc.h Normal file
View File

@ -0,0 +1,67 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* include/linux/nfs_ssc.h
*
* Author: Dai Ngo <dai.ngo@oracle.com>
*
* Copyright (c) 2020, Oracle and/or its affiliates.
*/
#include <linux/nfs_fs.h>
extern struct nfs_ssc_client_ops_tbl nfs_ssc_client_tbl;
/*
* NFS_V4
*/
struct nfs4_ssc_client_ops {
struct file *(*sco_open)(struct vfsmount *ss_mnt,
struct nfs_fh *src_fh, nfs4_stateid *stateid);
void (*sco_close)(struct file *filep);
};
/*
* NFS_FS
*/
struct nfs_ssc_client_ops {
void (*sco_sb_deactive)(struct super_block *sb);
};
struct nfs_ssc_client_ops_tbl {
const struct nfs4_ssc_client_ops *ssc_nfs4_ops;
const struct nfs_ssc_client_ops *ssc_nfs_ops;
};
extern void nfs42_ssc_register_ops(void);
extern void nfs42_ssc_unregister_ops(void);
extern void nfs42_ssc_register(const struct nfs4_ssc_client_ops *ops);
extern void nfs42_ssc_unregister(const struct nfs4_ssc_client_ops *ops);
#ifdef CONFIG_NFSD_V4_2_INTER_SSC
static inline struct file *nfs42_ssc_open(struct vfsmount *ss_mnt,
struct nfs_fh *src_fh, nfs4_stateid *stateid)
{
if (nfs_ssc_client_tbl.ssc_nfs4_ops)
return (*nfs_ssc_client_tbl.ssc_nfs4_ops->sco_open)(ss_mnt, src_fh, stateid);
return ERR_PTR(-EIO);
}
static inline void nfs42_ssc_close(struct file *filep)
{
if (nfs_ssc_client_tbl.ssc_nfs4_ops)
(*nfs_ssc_client_tbl.ssc_nfs4_ops->sco_close)(filep);
}
#endif
/*
* NFS_FS
*/
extern void nfs_ssc_register(const struct nfs_ssc_client_ops *ops);
extern void nfs_ssc_unregister(const struct nfs_ssc_client_ops *ops);
static inline void nfs_do_sb_deactive(struct super_block *sb)
{
if (nfs_ssc_client_tbl.ssc_nfs_ops)
(*nfs_ssc_client_tbl.ssc_nfs_ops->sco_sb_deactive)(sb);
}