mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'nfs-for-7.0-1' of git://git.linux-nfs.org/projects/anna/linux-nfs
Pull NFS client updates from Anna Schumaker:
"New Features:
- Use an LRU list for returning unused delegations
- Introduce a KConfig option to disable NFS v4.0 and make NFS v4.1
the default
Bugfixes:
- NFS/localio:
- Handle short writes by retrying
- Prevent direct reclaim recursion into NFS via nfs_writepages
- Use GFP_NOIO and non-memreclaim workqueue in nfs_local_commit
- Remove -EAGAIN handling in nfs_local_doio()
- pNFS: fix a missing wake up while waiting on NFS_LAYOUT_DRAIN
- fs/nfs: Fix a readdir slow-start regression
- SUNRPC: fix gss_auth kref leak in gss_alloc_msg error path
Other cleanups and improvements:
- A few other NFS/localio cleanups
- Various other delegation handling cleanups from Christoph
- Unify security_inode_listsecurity() calls
- Improvements to NFSv4 lease handling
- Clean up SUNRPC *_debug fields when CONFIG_SUNRPC_DEBUG is not set"
* tag 'nfs-for-7.0-1' of git://git.linux-nfs.org/projects/anna/linux-nfs: (60 commits)
SUNRPC: fix gss_auth kref leak in gss_alloc_msg error path
nfs: nfs4proc: Convert comma to semicolon
SUNRPC: Change list definition method
sunrpc: rpc_debug and others are defined even if CONFIG_SUNRPC_DEBUG unset
NFSv4: limit lease period in nfs4_set_lease_period()
NFSv4: pass lease period in seconds to nfs4_set_lease_period()
nfs: unify security_inode_listsecurity() calls
fs/nfs: Fix readdir slow-start regression
pNFS: fix a missing wake up while waiting on NFS_LAYOUT_DRAIN
NFS: fix delayed delegation return handling
NFS: simplify error handling in nfs_end_delegation_return
NFS: fold nfs_abort_delegation_return into nfs_end_delegation_return
NFS: remove the delegation == NULL check in nfs_end_delegation_return
NFS: use bool for the issync argument to nfs_end_delegation_return
NFS: return void from ->return_delegation
NFS: return void from nfs4_inode_make_writeable
NFS: Merge CONFIG_NFS_V4_1 with CONFIG_NFS_V4
NFS: Add a way to disable NFS v4.0 via KConfig
NFS: Move sequence slot operations into minorversion operations
NFS: Pass a struct nfs_client to nfs4_init_sequence()
...
This commit is contained in:
+13
-13
@@ -78,9 +78,10 @@ config NFS_V4
|
||||
tristate "NFS client support for NFS version 4"
|
||||
depends on NFS_FS
|
||||
select KEYS
|
||||
select SUNRPC_BACKCHANNEL
|
||||
help
|
||||
This option enables support for version 4 of the NFS protocol
|
||||
(RFC 3530) in the kernel's NFS client.
|
||||
This option enables support for version 4.1 of the NFS protocol
|
||||
(RFC 5661) in the kernel's NFS client.
|
||||
|
||||
To mount NFS servers using NFSv4, you also need to install user
|
||||
space programs which can be found in the Linux nfs-utils package,
|
||||
@@ -96,19 +97,18 @@ config NFS_SWAP
|
||||
help
|
||||
This option enables swapon to work on files located on NFS mounts.
|
||||
|
||||
config NFS_V4_1
|
||||
bool "NFS client support for NFSv4.1"
|
||||
config NFS_V4_0
|
||||
bool "NFS client support for NFSv4.0"
|
||||
depends on NFS_V4
|
||||
select SUNRPC_BACKCHANNEL
|
||||
help
|
||||
This option enables support for minor version 1 of the NFSv4 protocol
|
||||
(RFC 5661) in the kernel's NFS client.
|
||||
This option enables support for minor version 0 of the NFSv4 protocol
|
||||
(RFC 3530) in the kernel's NFS client.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config NFS_V4_2
|
||||
bool "NFS client support for NFSv4.2"
|
||||
depends on NFS_V4_1
|
||||
depends on NFS_V4
|
||||
help
|
||||
This option enables support for minor version 2 of the NFSv4 protocol
|
||||
in the kernel's NFS client.
|
||||
@@ -117,22 +117,22 @@ config NFS_V4_2
|
||||
|
||||
config PNFS_FILE_LAYOUT
|
||||
tristate
|
||||
depends on NFS_V4_1
|
||||
depends on NFS_V4
|
||||
default NFS_V4
|
||||
|
||||
config PNFS_BLOCK
|
||||
tristate
|
||||
depends on NFS_V4_1 && BLK_DEV_DM
|
||||
depends on NFS_V4 && BLK_DEV_DM
|
||||
default NFS_V4
|
||||
|
||||
config PNFS_FLEXFILE_LAYOUT
|
||||
tristate
|
||||
depends on NFS_V4_1
|
||||
depends on NFS_V4
|
||||
default NFS_V4
|
||||
|
||||
config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN
|
||||
string "NFSv4.1 Implementation ID Domain"
|
||||
depends on NFS_V4_1
|
||||
depends on NFS_V4
|
||||
default "kernel.org"
|
||||
help
|
||||
This option defines the domain portion of the implementation ID that
|
||||
@@ -144,7 +144,7 @@ config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN
|
||||
|
||||
config NFS_V4_1_MIGRATION
|
||||
bool "NFSv4.1 client support for migration"
|
||||
depends on NFS_V4_1
|
||||
depends on NFS_V4
|
||||
default n
|
||||
help
|
||||
This option makes the NFS client advertise to NFSv4.1 servers that
|
||||
|
||||
+2
-2
@@ -27,10 +27,10 @@ CFLAGS_nfs4trace.o += -I$(src)
|
||||
nfsv4-y := nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o nfs4super.o nfs4file.o \
|
||||
delegation.o nfs4idmap.o callback.o callback_xdr.o callback_proc.o \
|
||||
nfs4namespace.o nfs4getroot.o nfs4client.o nfs4session.o \
|
||||
dns_resolve.o nfs4trace.o
|
||||
dns_resolve.o nfs4trace.o pnfs.o pnfs_dev.o pnfs_nfs.o
|
||||
nfsv4-$(CONFIG_NFS_USE_LEGACY_DNS) += cache_lib.o
|
||||
nfsv4-$(CONFIG_SYSCTL) += nfs4sysctl.o
|
||||
nfsv4-$(CONFIG_NFS_V4_1) += pnfs.o pnfs_dev.o pnfs_nfs.o
|
||||
nfsv4-$(CONFIG_NFS_V4_0) += nfs40client.o nfs40proc.o
|
||||
nfsv4-$(CONFIG_NFS_V4_2) += nfs42proc.o nfs42xattr.o
|
||||
|
||||
obj-$(CONFIG_PNFS_FILE_LAYOUT) += filelayout/
|
||||
|
||||
+1
-12
@@ -87,7 +87,6 @@ nfs4_callback_svc(void *vrqstp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
|
||||
struct svc_serv *serv)
|
||||
{
|
||||
@@ -98,12 +97,6 @@ static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
|
||||
*/
|
||||
xprt->bc_serv = serv;
|
||||
}
|
||||
#else
|
||||
static inline void nfs_callback_bc_serv(u32 minorversion, struct rpc_xprt *xprt,
|
||||
struct svc_serv *serv)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
||||
static int nfs_callback_start_svc(int minorversion, struct rpc_xprt *xprt,
|
||||
struct svc_serv *serv)
|
||||
@@ -157,7 +150,7 @@ static int nfs_callback_up_net(int minorversion, struct svc_serv *serv,
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
if (!IS_ENABLED(CONFIG_NFS_V4_1) || minorversion == 0)
|
||||
if (minorversion == 0)
|
||||
ret = nfs4_callback_up_net(serv, net);
|
||||
else if (xprt->ops->bc_setup)
|
||||
set_bc_enabled(serv);
|
||||
@@ -198,10 +191,6 @@ static struct svc_serv *nfs_callback_create_svc(int minorversion)
|
||||
cb_info->users);
|
||||
|
||||
threadfn = nfs4_callback_svc;
|
||||
#if !defined(CONFIG_NFS_V4_1)
|
||||
if (minorversion)
|
||||
return ERR_PTR(-ENOTSUPP);
|
||||
#endif
|
||||
serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE,
|
||||
threadfn);
|
||||
if (!serv) {
|
||||
|
||||
@@ -65,8 +65,6 @@ struct cb_recallargs {
|
||||
uint32_t truncate;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
|
||||
struct referring_call {
|
||||
uint32_t rc_sequenceid;
|
||||
uint32_t rc_slotid;
|
||||
@@ -168,7 +166,6 @@ struct cb_notify_lock_args {
|
||||
|
||||
extern __be32 nfs4_callback_notify_lock(void *argp, void *resp,
|
||||
struct cb_process_state *cps);
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
struct cb_offloadargs {
|
||||
struct nfs_fh coa_fh;
|
||||
|
||||
@@ -51,12 +51,18 @@ __be32 nfs4_callback_getattr(void *argp, void *resp,
|
||||
-ntohl(res->status));
|
||||
goto out;
|
||||
}
|
||||
rcu_read_lock();
|
||||
|
||||
delegation = nfs4_get_valid_delegation(inode);
|
||||
if (delegation == NULL || (delegation->type & FMODE_WRITE) == 0)
|
||||
if (!delegation)
|
||||
goto out_iput;
|
||||
res->size = i_size_read(inode);
|
||||
if ((delegation->type & FMODE_WRITE) == 0) {
|
||||
nfs_put_delegation(delegation);
|
||||
goto out_iput;
|
||||
}
|
||||
res->change_attr = delegation->change_attr;
|
||||
nfs_put_delegation(delegation);
|
||||
|
||||
res->size = i_size_read(inode);
|
||||
if (nfs_have_writebacks(inode))
|
||||
res->change_attr++;
|
||||
res->atime = inode_get_atime(inode);
|
||||
@@ -71,7 +77,6 @@ __be32 nfs4_callback_getattr(void *argp, void *resp,
|
||||
FATTR4_WORD2_TIME_DELEG_MODIFY) & args->bitmap[2];
|
||||
res->status = 0;
|
||||
out_iput:
|
||||
rcu_read_unlock();
|
||||
trace_nfs4_cb_getattr(cps->clp, &args->fh, inode, -ntohl(res->status));
|
||||
nfs_iput_and_deactive(inode);
|
||||
out:
|
||||
@@ -121,8 +126,6 @@ out:
|
||||
return res;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
|
||||
/*
|
||||
* Lookup a layout inode by stateid
|
||||
*
|
||||
@@ -693,7 +696,6 @@ __be32 nfs4_callback_notify_lock(void *argp, void *resp,
|
||||
|
||||
return htonl(NFS4_OK);
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
static void nfs4_copy_cb_args(struct nfs4_copy_state *cp_state,
|
||||
struct cb_offloadargs *args)
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
(2 + 2 + 3 + 3 + 3 + 3 + 3) * 4)
|
||||
#define CB_OP_RECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
|
||||
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
#define CB_OP_LAYOUTRECALL_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
|
||||
#define CB_OP_DEVICENOTIFY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
|
||||
#define CB_OP_SEQUENCE_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ + \
|
||||
@@ -39,7 +38,6 @@
|
||||
#define CB_OP_RECALLANY_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
|
||||
#define CB_OP_RECALLSLOT_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
|
||||
#define CB_OP_NOTIFY_LOCK_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
#define CB_OP_OFFLOAD_RES_MAXSZ (CB_OP_HDR_RES_MAXSZ)
|
||||
#endif /* CONFIG_NFS_V4_2 */
|
||||
@@ -205,7 +203,6 @@ static __be32 decode_recall_args(struct svc_rqst *rqstp,
|
||||
return decode_fh(xdr, &args->fh);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
static __be32 decode_layout_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
|
||||
{
|
||||
stateid->type = NFS4_LAYOUT_STATEID_TYPE;
|
||||
@@ -521,7 +518,6 @@ static __be32 decode_notify_lock_args(struct svc_rqst *rqstp,
|
||||
return decode_lockowner(xdr, args);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
static __be32 decode_write_response(struct xdr_stream *xdr,
|
||||
struct cb_offloadargs *args)
|
||||
@@ -747,8 +743,6 @@ out:
|
||||
return status;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
|
||||
static __be32 encode_sessionid(struct xdr_stream *xdr,
|
||||
const struct nfs4_sessionid *sid)
|
||||
{
|
||||
@@ -846,19 +840,6 @@ static void nfs4_cb_free_slot(struct cb_process_state *cps)
|
||||
}
|
||||
}
|
||||
|
||||
#else /* CONFIG_NFS_V4_1 */
|
||||
|
||||
static __be32
|
||||
preprocess_nfs41_op(int nop, unsigned int op_nr, struct callback_op **op)
|
||||
{
|
||||
return htonl(NFS4ERR_MINOR_VERS_MISMATCH);
|
||||
}
|
||||
|
||||
static void nfs4_cb_free_slot(struct cb_process_state *cps)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
static __be32
|
||||
preprocess_nfs42_op(int nop, unsigned int op_nr, struct callback_op **op)
|
||||
@@ -1051,7 +1032,6 @@ static struct callback_op callback_ops[] = {
|
||||
.decode_args = decode_recall_args,
|
||||
.res_maxsize = CB_OP_RECALL_RES_MAXSZ,
|
||||
},
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
[OP_CB_LAYOUTRECALL] = {
|
||||
.process_op = nfs4_callback_layoutrecall,
|
||||
.decode_args = decode_layoutrecall_args,
|
||||
@@ -1083,7 +1063,6 @@ static struct callback_op callback_ops[] = {
|
||||
.decode_args = decode_notify_lock_args,
|
||||
.res_maxsize = CB_OP_NOTIFY_LOCK_RES_MAXSZ,
|
||||
},
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
[OP_CB_OFFLOAD] = {
|
||||
.process_op = nfs4_callback_offload,
|
||||
|
||||
+7
-5
@@ -1060,6 +1060,10 @@ struct nfs_server *nfs_alloc_server(void)
|
||||
INIT_LIST_HEAD(&server->client_link);
|
||||
INIT_LIST_HEAD(&server->master_link);
|
||||
INIT_LIST_HEAD(&server->delegations);
|
||||
spin_lock_init(&server->delegations_lock);
|
||||
INIT_LIST_HEAD(&server->delegations_return);
|
||||
INIT_LIST_HEAD(&server->delegations_lru);
|
||||
INIT_LIST_HEAD(&server->delegations_delayed);
|
||||
INIT_LIST_HEAD(&server->layouts);
|
||||
INIT_LIST_HEAD(&server->state_owners_lru);
|
||||
INIT_LIST_HEAD(&server->ss_copies);
|
||||
@@ -1263,11 +1267,9 @@ void nfs_clients_init(struct net *net)
|
||||
INIT_LIST_HEAD(&nn->nfs_volume_list);
|
||||
#if IS_ENABLED(CONFIG_NFS_V4)
|
||||
idr_init(&nn->cb_ident_idr);
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_NFS_V4_1)
|
||||
INIT_LIST_HEAD(&nn->nfs4_data_server_cache);
|
||||
spin_lock_init(&nn->nfs4_data_server_lock);
|
||||
#endif
|
||||
#endif /* CONFIG_NFS_V4 */
|
||||
spin_lock_init(&nn->nfs_client_lock);
|
||||
nn->boot_time = ktime_get_real();
|
||||
memset(&nn->rpcstats, 0, sizeof(nn->rpcstats));
|
||||
@@ -1284,9 +1286,9 @@ void nfs_clients_exit(struct net *net)
|
||||
nfs_cleanup_cb_ident_idr(net);
|
||||
WARN_ON_ONCE(!list_empty(&nn->nfs_client_list));
|
||||
WARN_ON_ONCE(!list_empty(&nn->nfs_volume_list));
|
||||
#if IS_ENABLED(CONFIG_NFS_V4_1)
|
||||
#if IS_ENABLED(CONFIG_NFS_V4)
|
||||
WARN_ON_ONCE(!list_empty(&nn->nfs4_data_server_cache));
|
||||
#endif
|
||||
#endif /* CONFIG_NFS_V4 */
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
+299
-305
File diff suppressed because it is too large
Load Diff
+4
-5
@@ -26,19 +26,17 @@ struct nfs_delegation {
|
||||
unsigned long flags;
|
||||
refcount_t refcount;
|
||||
spinlock_t lock;
|
||||
struct list_head entry;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
enum {
|
||||
NFS_DELEGATION_NEED_RECLAIM = 0,
|
||||
NFS_DELEGATION_RETURN,
|
||||
NFS_DELEGATION_RETURN_IF_CLOSED,
|
||||
NFS_DELEGATION_REFERENCED,
|
||||
NFS_DELEGATION_RETURNING,
|
||||
NFS_DELEGATION_REVOKED,
|
||||
NFS_DELEGATION_TEST_EXPIRED,
|
||||
NFS_DELEGATION_INODE_FREEING,
|
||||
NFS_DELEGATION_RETURN_DELAYED,
|
||||
NFS_DELEGATION_DELEGTIME,
|
||||
};
|
||||
|
||||
@@ -48,7 +46,7 @@ int nfs_inode_set_delegation(struct inode *inode, const struct cred *cred,
|
||||
void nfs_inode_reclaim_delegation(struct inode *inode, const struct cred *cred,
|
||||
fmode_t type, const nfs4_stateid *stateid,
|
||||
unsigned long pagemod_limit, u32 deleg_type);
|
||||
int nfs4_inode_return_delegation(struct inode *inode);
|
||||
void nfs4_inode_return_delegation(struct inode *inode);
|
||||
void nfs4_inode_return_delegation_on_close(struct inode *inode);
|
||||
void nfs4_inode_set_return_delegation_on_close(struct inode *inode);
|
||||
int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
|
||||
@@ -81,13 +79,14 @@ bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags, nfs4_state
|
||||
bool nfs4_refresh_delegation_stateid(nfs4_stateid *dst, struct inode *inode);
|
||||
|
||||
struct nfs_delegation *nfs4_get_valid_delegation(const struct inode *inode);
|
||||
void nfs_put_delegation(struct nfs_delegation *delegation);
|
||||
void nfs_mark_delegation_referenced(struct nfs_delegation *delegation);
|
||||
int nfs4_have_delegation(struct inode *inode, fmode_t type, int flags);
|
||||
int nfs4_check_delegation(struct inode *inode, fmode_t type);
|
||||
bool nfs4_delegation_flush_on_close(const struct inode *inode);
|
||||
void nfs_inode_find_delegation_state_and_recover(struct inode *inode,
|
||||
const nfs4_stateid *stateid);
|
||||
int nfs4_inode_make_writeable(struct inode *inode);
|
||||
void nfs4_inode_make_writeable(struct inode *inode);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
+2
-2
@@ -72,7 +72,7 @@ const struct address_space_operations nfs_dir_aops = {
|
||||
.free_folio = nfs_readdir_clear_array,
|
||||
};
|
||||
|
||||
#define NFS_INIT_DTSIZE PAGE_SIZE
|
||||
#define NFS_INIT_DTSIZE SZ_64K
|
||||
|
||||
static struct nfs_open_dir_context *
|
||||
alloc_nfs_open_dir_context(struct inode *dir)
|
||||
@@ -83,7 +83,7 @@ alloc_nfs_open_dir_context(struct inode *dir)
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL_ACCOUNT);
|
||||
if (ctx != NULL) {
|
||||
ctx->attr_gencount = nfsi->attr_gencount;
|
||||
ctx->dtsize = NFS_INIT_DTSIZE;
|
||||
ctx->dtsize = min(NFS_SERVER(dir)->dtsize, NFS_INIT_DTSIZE);
|
||||
spin_lock(&dir->i_lock);
|
||||
if (list_empty(&nfsi->open_files) &&
|
||||
(nfsi->cache_validity & NFS_INO_DATA_INVAL_DEFER))
|
||||
|
||||
+2
-1
@@ -806,7 +806,8 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
|
||||
ctx->mount_server.version = result.uint_32;
|
||||
break;
|
||||
case Opt_minorversion:
|
||||
if (result.uint_32 > NFS4_MAX_MINOR_VERSION)
|
||||
if (result.uint_32 < NFS4_MIN_MINOR_VERSION ||
|
||||
result.uint_32 > NFS4_MAX_MINOR_VERSION)
|
||||
goto out_of_bounds;
|
||||
ctx->minorversion = result.uint_32;
|
||||
break;
|
||||
|
||||
+4
-11
@@ -334,17 +334,13 @@ extern int nfs3_decode_dirent(struct xdr_stream *,
|
||||
#if IS_ENABLED(CONFIG_NFS_V4)
|
||||
extern int nfs4_decode_dirent(struct xdr_stream *,
|
||||
struct nfs_entry *, bool);
|
||||
#endif
|
||||
#ifdef CONFIG_NFS_V4_1
|
||||
extern const u32 nfs41_maxread_overhead;
|
||||
extern const u32 nfs41_maxwrite_overhead;
|
||||
extern const u32 nfs41_maxgetdevinfo_overhead;
|
||||
#endif
|
||||
|
||||
/* nfs4proc.c */
|
||||
#if IS_ENABLED(CONFIG_NFS_V4)
|
||||
extern const struct rpc_procinfo nfs4_procedures[];
|
||||
#endif
|
||||
#endif /* CONFIG_NFS_V4 */
|
||||
|
||||
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
|
||||
extern struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags);
|
||||
@@ -639,7 +635,7 @@ void nfs_pageio_stop_mirroring(struct nfs_pageio_descriptor *pgio);
|
||||
int nfs_filemap_write_and_wait_range(struct address_space *mapping,
|
||||
loff_t lstart, loff_t lend);
|
||||
|
||||
#ifdef CONFIG_NFS_V4_1
|
||||
#ifdef CONFIG_NFS_V4
|
||||
static inline void
|
||||
pnfs_bucket_clear_pnfs_ds_commit_verifiers(struct pnfs_commit_bucket *buckets,
|
||||
unsigned int nbuckets)
|
||||
@@ -660,12 +656,12 @@ void nfs_clear_pnfs_ds_commit_verifiers(struct pnfs_ds_commit_info *cinfo)
|
||||
array->nbuckets);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
#else
|
||||
#else /* CONFIG_NFS_V4 */
|
||||
static inline
|
||||
void nfs_clear_pnfs_ds_commit_verifiers(struct pnfs_ds_commit_info *cinfo)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_NFS_V4 */
|
||||
|
||||
#ifdef CONFIG_MIGRATION
|
||||
int nfs_migrate_folio(struct address_space *, struct folio *dst,
|
||||
@@ -739,9 +735,6 @@ extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq, loff_t offset);
|
||||
/* nfs4proc.c */
|
||||
extern struct nfs_client *nfs4_init_client(struct nfs_client *clp,
|
||||
const struct nfs_client_initdata *);
|
||||
extern int nfs40_walk_client_list(struct nfs_client *clp,
|
||||
struct nfs_client **result,
|
||||
const struct cred *cred);
|
||||
extern int nfs41_walk_client_list(struct nfs_client *clp,
|
||||
struct nfs_client **result,
|
||||
const struct cred *cred);
|
||||
|
||||
+82
-44
@@ -58,6 +58,11 @@ struct nfs_local_fsync_ctx {
|
||||
static bool localio_enabled __read_mostly = true;
|
||||
module_param(localio_enabled, bool, 0644);
|
||||
|
||||
static void nfs_local_do_read(struct nfs_local_kiocb *iocb,
|
||||
const struct rpc_call_ops *call_ops);
|
||||
static void nfs_local_do_write(struct nfs_local_kiocb *iocb,
|
||||
const struct rpc_call_ops *call_ops);
|
||||
|
||||
static inline bool nfs_client_is_local(const struct nfs_client *clp)
|
||||
{
|
||||
return !!rcu_access_pointer(clp->cl_uuid.net);
|
||||
@@ -286,6 +291,18 @@ nfs_local_open_fh(struct nfs_client *clp, const struct cred *cred,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_local_open_fh);
|
||||
|
||||
/*
|
||||
* Ensure all page cache allocations are done from GFP_NOFS context to
|
||||
* prevent direct reclaim recursion back into NFS via nfs_writepages.
|
||||
*/
|
||||
static void
|
||||
nfs_local_mapping_set_gfp_nofs_context(struct address_space *m)
|
||||
{
|
||||
gfp_t gfp_mask = mapping_gfp_mask(m);
|
||||
|
||||
mapping_set_gfp_mask(m, (gfp_mask & ~(__GFP_FS)));
|
||||
}
|
||||
|
||||
static void
|
||||
nfs_local_iocb_free(struct nfs_local_kiocb *iocb)
|
||||
{
|
||||
@@ -310,6 +327,7 @@ nfs_local_iocb_alloc(struct nfs_pgio_header *hdr,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nfs_local_mapping_set_gfp_nofs_context(file->f_mapping);
|
||||
init_sync_kiocb(&iocb->kiocb, file);
|
||||
|
||||
iocb->hdr = hdr;
|
||||
@@ -512,8 +530,7 @@ nfs_local_pgio_init(struct nfs_pgio_header *hdr,
|
||||
hdr->task.tk_start = ktime_get();
|
||||
}
|
||||
|
||||
static bool
|
||||
nfs_local_pgio_done(struct nfs_local_kiocb *iocb, long status, bool force)
|
||||
static bool nfs_local_pgio_done(struct nfs_local_kiocb *iocb, long status)
|
||||
{
|
||||
struct nfs_pgio_header *hdr = iocb->hdr;
|
||||
|
||||
@@ -528,9 +545,6 @@ nfs_local_pgio_done(struct nfs_local_kiocb *iocb, long status, bool force)
|
||||
hdr->task.tk_status = status;
|
||||
}
|
||||
|
||||
if (force)
|
||||
return true;
|
||||
|
||||
BUG_ON(atomic_read(&iocb->n_iters) <= 0);
|
||||
return atomic_dec_and_test(&iocb->n_iters);
|
||||
}
|
||||
@@ -542,13 +556,50 @@ nfs_local_iocb_release(struct nfs_local_kiocb *iocb)
|
||||
nfs_local_iocb_free(iocb);
|
||||
}
|
||||
|
||||
static void
|
||||
nfs_local_pgio_release(struct nfs_local_kiocb *iocb)
|
||||
static void nfs_local_pgio_restart(struct nfs_local_kiocb *iocb,
|
||||
struct nfs_pgio_header *hdr)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
iocb->kiocb.ki_pos = hdr->args.offset;
|
||||
iocb->kiocb.ki_flags &= ~(IOCB_DSYNC | IOCB_SYNC | IOCB_DIRECT);
|
||||
iocb->kiocb.ki_complete = NULL;
|
||||
iocb->aio_complete_work = NULL;
|
||||
iocb->end_iter_index = -1;
|
||||
|
||||
switch (hdr->rw_mode) {
|
||||
case FMODE_READ:
|
||||
nfs_local_iters_init(iocb, ITER_DEST);
|
||||
nfs_local_do_read(iocb, hdr->task.tk_ops);
|
||||
break;
|
||||
case FMODE_WRITE:
|
||||
nfs_local_iters_init(iocb, ITER_SOURCE);
|
||||
nfs_local_do_write(iocb, hdr->task.tk_ops);
|
||||
break;
|
||||
default:
|
||||
status = -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (unlikely(status != 0)) {
|
||||
nfs_local_iocb_release(iocb);
|
||||
hdr->task.tk_status = status;
|
||||
nfs_local_hdr_release(hdr, hdr->task.tk_ops);
|
||||
}
|
||||
}
|
||||
|
||||
static void nfs_local_pgio_release(struct nfs_local_kiocb *iocb)
|
||||
{
|
||||
struct nfs_pgio_header *hdr = iocb->hdr;
|
||||
struct rpc_task *task = &hdr->task;
|
||||
|
||||
nfs_local_iocb_release(iocb);
|
||||
nfs_local_hdr_release(hdr, hdr->task.tk_ops);
|
||||
task->tk_action = NULL;
|
||||
task->tk_ops->rpc_call_done(task, hdr);
|
||||
|
||||
if (task->tk_action == NULL) {
|
||||
nfs_local_iocb_release(iocb);
|
||||
task->tk_ops->rpc_release(hdr);
|
||||
} else
|
||||
nfs_local_pgio_restart(iocb, hdr);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -609,7 +660,7 @@ static void nfs_local_read_aio_complete(struct kiocb *kiocb, long ret)
|
||||
container_of(kiocb, struct nfs_local_kiocb, kiocb);
|
||||
|
||||
/* AIO completion of DIO read should always be last to complete */
|
||||
if (unlikely(!nfs_local_pgio_done(iocb, ret, false)))
|
||||
if (unlikely(!nfs_local_pgio_done(iocb, ret)))
|
||||
return;
|
||||
|
||||
nfs_local_pgio_aio_complete(iocb); /* Calls nfs_local_read_aio_complete_work */
|
||||
@@ -641,7 +692,7 @@ static void nfs_local_call_read(struct work_struct *work)
|
||||
if (status == -EIOCBQUEUED)
|
||||
continue;
|
||||
/* Break on completion, errors, or short reads */
|
||||
if (nfs_local_pgio_done(iocb, status, false) || status < 0 ||
|
||||
if (nfs_local_pgio_done(iocb, status) || status < 0 ||
|
||||
(size_t)status < iov_iter_count(&iocb->iters[i])) {
|
||||
nfs_local_read_iocb_done(iocb);
|
||||
break;
|
||||
@@ -649,9 +700,8 @@ static void nfs_local_call_read(struct work_struct *work)
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
nfs_local_do_read(struct nfs_local_kiocb *iocb,
|
||||
const struct rpc_call_ops *call_ops)
|
||||
static void nfs_local_do_read(struct nfs_local_kiocb *iocb,
|
||||
const struct rpc_call_ops *call_ops)
|
||||
{
|
||||
struct nfs_pgio_header *hdr = iocb->hdr;
|
||||
|
||||
@@ -663,8 +713,6 @@ nfs_local_do_read(struct nfs_local_kiocb *iocb,
|
||||
|
||||
INIT_WORK(&iocb->work, nfs_local_call_read);
|
||||
queue_work(nfslocaliod_workqueue, &iocb->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -773,19 +821,7 @@ static void nfs_local_write_done(struct nfs_local_kiocb *iocb)
|
||||
pr_info_ratelimited("nfs: Unexpected direct I/O write alignment failure\n");
|
||||
}
|
||||
|
||||
/* Handle short writes as if they are ENOSPC */
|
||||
status = hdr->res.count;
|
||||
if (status > 0 && status < hdr->args.count) {
|
||||
hdr->mds_offset += status;
|
||||
hdr->args.offset += status;
|
||||
hdr->args.pgbase += status;
|
||||
hdr->args.count -= status;
|
||||
nfs_set_pgio_error(hdr, -ENOSPC, hdr->args.offset);
|
||||
status = -ENOSPC;
|
||||
/* record -ENOSPC in terms of nfs_local_pgio_done */
|
||||
(void) nfs_local_pgio_done(iocb, status, true);
|
||||
}
|
||||
if (hdr->task.tk_status < 0)
|
||||
if (status < 0)
|
||||
nfs_reset_boot_verifier(hdr->inode);
|
||||
}
|
||||
|
||||
@@ -810,7 +846,7 @@ static void nfs_local_write_aio_complete(struct kiocb *kiocb, long ret)
|
||||
container_of(kiocb, struct nfs_local_kiocb, kiocb);
|
||||
|
||||
/* AIO completion of DIO write should always be last to complete */
|
||||
if (unlikely(!nfs_local_pgio_done(iocb, ret, false)))
|
||||
if (unlikely(!nfs_local_pgio_done(iocb, ret)))
|
||||
return;
|
||||
|
||||
nfs_local_pgio_aio_complete(iocb); /* Calls nfs_local_write_aio_complete_work */
|
||||
@@ -846,7 +882,7 @@ static void nfs_local_call_write(struct work_struct *work)
|
||||
if (status == -EIOCBQUEUED)
|
||||
continue;
|
||||
/* Break on completion, errors, or short writes */
|
||||
if (nfs_local_pgio_done(iocb, status, false) || status < 0 ||
|
||||
if (nfs_local_pgio_done(iocb, status) || status < 0 ||
|
||||
(size_t)status < iov_iter_count(&iocb->iters[i])) {
|
||||
nfs_local_write_iocb_done(iocb);
|
||||
break;
|
||||
@@ -857,9 +893,8 @@ static void nfs_local_call_write(struct work_struct *work)
|
||||
current->flags = old_flags;
|
||||
}
|
||||
|
||||
static int
|
||||
nfs_local_do_write(struct nfs_local_kiocb *iocb,
|
||||
const struct rpc_call_ops *call_ops)
|
||||
static void nfs_local_do_write(struct nfs_local_kiocb *iocb,
|
||||
const struct rpc_call_ops *call_ops)
|
||||
{
|
||||
struct nfs_pgio_header *hdr = iocb->hdr;
|
||||
|
||||
@@ -883,8 +918,6 @@ nfs_local_do_write(struct nfs_local_kiocb *iocb,
|
||||
|
||||
INIT_WORK(&iocb->work, nfs_local_call_write);
|
||||
queue_work(nfslocaliod_workqueue, &iocb->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct nfs_local_kiocb *
|
||||
@@ -934,10 +967,10 @@ int nfs_local_doio(struct nfs_client *clp, struct nfsd_file *localio,
|
||||
|
||||
switch (hdr->rw_mode) {
|
||||
case FMODE_READ:
|
||||
status = nfs_local_do_read(iocb, call_ops);
|
||||
nfs_local_do_read(iocb, call_ops);
|
||||
break;
|
||||
case FMODE_WRITE:
|
||||
status = nfs_local_do_write(iocb, call_ops);
|
||||
nfs_local_do_write(iocb, call_ops);
|
||||
break;
|
||||
default:
|
||||
dprintk("%s: invalid mode: %d\n", __func__,
|
||||
@@ -945,9 +978,7 @@ int nfs_local_doio(struct nfs_client *clp, struct nfsd_file *localio,
|
||||
status = -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (status != 0) {
|
||||
if (status == -EAGAIN)
|
||||
nfs_localio_disable_client(clp);
|
||||
if (unlikely(status != 0)) {
|
||||
nfs_local_iocb_release(iocb);
|
||||
hdr->task.tk_status = status;
|
||||
nfs_local_hdr_release(hdr, call_ops);
|
||||
@@ -974,6 +1005,8 @@ nfs_local_run_commit(struct file *filp, struct nfs_commit_data *data)
|
||||
end = LLONG_MAX;
|
||||
}
|
||||
|
||||
nfs_local_mapping_set_gfp_nofs_context(filp->f_mapping);
|
||||
|
||||
dprintk("%s: commit %llu - %llu\n", __func__, start, end);
|
||||
return vfs_fsync_range(filp, start, end, 0);
|
||||
}
|
||||
@@ -1015,17 +1048,22 @@ nfs_local_fsync_ctx_free(struct nfs_local_fsync_ctx *ctx)
|
||||
static void
|
||||
nfs_local_fsync_work(struct work_struct *work)
|
||||
{
|
||||
unsigned long old_flags = current->flags;
|
||||
struct nfs_local_fsync_ctx *ctx;
|
||||
int status;
|
||||
|
||||
ctx = container_of(work, struct nfs_local_fsync_ctx, work);
|
||||
|
||||
current->flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO;
|
||||
|
||||
status = nfs_local_run_commit(nfs_to->nfsd_file_file(ctx->localio),
|
||||
ctx->data);
|
||||
nfs_local_commit_done(ctx->data, status);
|
||||
if (ctx->done != NULL)
|
||||
complete(ctx->done);
|
||||
nfs_local_fsync_ctx_free(ctx);
|
||||
|
||||
current->flags = old_flags;
|
||||
}
|
||||
|
||||
static struct nfs_local_fsync_ctx *
|
||||
@@ -1049,7 +1087,7 @@ int nfs_local_commit(struct nfsd_file *localio,
|
||||
{
|
||||
struct nfs_local_fsync_ctx *ctx;
|
||||
|
||||
ctx = nfs_local_fsync_ctx_alloc(data, localio, GFP_KERNEL);
|
||||
ctx = nfs_local_fsync_ctx_alloc(data, localio, GFP_NOIO);
|
||||
if (!ctx) {
|
||||
nfs_local_commit_done(data, -ENOMEM);
|
||||
nfs_local_release_commit_data(localio, data, call_ops);
|
||||
@@ -1061,10 +1099,10 @@ int nfs_local_commit(struct nfsd_file *localio,
|
||||
if (how & FLUSH_SYNC) {
|
||||
DECLARE_COMPLETION_ONSTACK(done);
|
||||
ctx->done = &done;
|
||||
queue_work(nfsiod_workqueue, &ctx->work);
|
||||
queue_work(nfslocaliod_workqueue, &ctx->work);
|
||||
wait_for_completion(&done);
|
||||
} else
|
||||
queue_work(nfsiod_workqueue, &ctx->work);
|
||||
queue_work(nfslocaliod_workqueue, &ctx->work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
+1
-3
@@ -31,11 +31,9 @@ struct nfs_net {
|
||||
unsigned short nfs_callback_tcpport;
|
||||
unsigned short nfs_callback_tcpport6;
|
||||
int cb_users[NFS4_MAX_MINOR_VERSION + 1];
|
||||
#endif /* CONFIG_NFS_V4 */
|
||||
#if IS_ENABLED(CONFIG_NFS_V4_1)
|
||||
struct list_head nfs4_data_server_cache;
|
||||
spinlock_t nfs4_data_server_lock;
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
#endif /* CONFIG_NFS_V4 */
|
||||
struct nfs_netns_client *nfs_client;
|
||||
spinlock_t nfs_client_lock;
|
||||
ktime_t boot_time;
|
||||
|
||||
+1
-2
@@ -1027,11 +1027,10 @@ static int nfs3_have_delegation(struct inode *inode, fmode_t type, int flags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfs3_return_delegation(struct inode *inode)
|
||||
static void nfs3_return_delegation(struct inode *inode)
|
||||
{
|
||||
if (S_ISREG(inode->i_mode))
|
||||
nfs_wb_all(inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct inode_operations nfs3_dir_inode_operations = {
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#ifndef __LINUX_FS_NFS_NFS4_0_H
|
||||
#define __LINUX_FS_NFS_NFS4_0_H
|
||||
|
||||
|
||||
/* nfs40client.c */
|
||||
void nfs40_shutdown_client(struct nfs_client *);
|
||||
int nfs40_init_client(struct nfs_client *);
|
||||
void nfs40_handle_cb_pathdown(struct nfs_client *clp);
|
||||
|
||||
/* nfs40proc.c */
|
||||
extern const struct nfs4_minor_version_ops nfs_v4_0_minor_ops;
|
||||
|
||||
/* nfs40state.c */
|
||||
int nfs40_discover_server_trunking(struct nfs_client *clp,
|
||||
struct nfs_client **result,
|
||||
const struct cred *cred);
|
||||
|
||||
#endif /* __LINUX_FS_NFS_NFS4_0_H */
|
||||
@@ -0,0 +1,245 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#include <linux/nfs_fs.h>
|
||||
#include "nfs4_fs.h"
|
||||
#include "nfs4session.h"
|
||||
#include "callback.h"
|
||||
#include "delegation.h"
|
||||
#include "internal.h"
|
||||
#include "netns.h"
|
||||
#include "nfs40.h"
|
||||
|
||||
#define NFSDBG_FACILITY NFSDBG_CLIENT
|
||||
|
||||
/*
|
||||
* SETCLIENTID just did a callback update with the callback ident in
|
||||
* "drop," but server trunking discovery claims "drop" and "keep" are
|
||||
* actually the same server. Swap the callback IDs so that "keep"
|
||||
* will continue to use the callback ident the server now knows about,
|
||||
* and so that "keep"'s original callback ident is destroyed when
|
||||
* "drop" is freed.
|
||||
*/
|
||||
static void nfs4_swap_callback_idents(struct nfs_client *keep,
|
||||
struct nfs_client *drop)
|
||||
{
|
||||
struct nfs_net *nn = net_generic(keep->cl_net, nfs_net_id);
|
||||
unsigned int save = keep->cl_cb_ident;
|
||||
|
||||
if (keep->cl_cb_ident == drop->cl_cb_ident)
|
||||
return;
|
||||
|
||||
dprintk("%s: keeping callback ident %u and dropping ident %u\n",
|
||||
__func__, keep->cl_cb_ident, drop->cl_cb_ident);
|
||||
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
|
||||
idr_replace(&nn->cb_ident_idr, keep, drop->cl_cb_ident);
|
||||
keep->cl_cb_ident = drop->cl_cb_ident;
|
||||
|
||||
idr_replace(&nn->cb_ident_idr, drop, save);
|
||||
drop->cl_cb_ident = save;
|
||||
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
}
|
||||
|
||||
static bool nfs4_same_verifier(nfs4_verifier *v1, nfs4_verifier *v2)
|
||||
{
|
||||
return memcmp(v1->data, v2->data, sizeof(v1->data)) == 0;
|
||||
}
|
||||
|
||||
void nfs40_shutdown_client(struct nfs_client *clp)
|
||||
{
|
||||
if (clp->cl_slot_tbl) {
|
||||
nfs4_shutdown_slot_table(clp->cl_slot_tbl);
|
||||
kfree(clp->cl_slot_tbl);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs40_init_client - nfs_client initialization tasks for NFSv4.0
|
||||
* @clp: nfs_client to initialize
|
||||
*
|
||||
* Returns zero on success, or a negative errno if some error occurred.
|
||||
*/
|
||||
int nfs40_init_client(struct nfs_client *clp)
|
||||
{
|
||||
struct nfs4_slot_table *tbl;
|
||||
int ret;
|
||||
|
||||
tbl = kzalloc(sizeof(*tbl), GFP_NOFS);
|
||||
if (tbl == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = nfs4_setup_slot_table(tbl, NFS4_MAX_SLOT_TABLE,
|
||||
"NFSv4.0 transport Slot table");
|
||||
if (ret) {
|
||||
nfs4_shutdown_slot_table(tbl);
|
||||
kfree(tbl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
clp->cl_slot_tbl = tbl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* nfs40_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN
|
||||
* @clp: client to process
|
||||
*
|
||||
* Set the NFS4CLNT_LEASE_EXPIRED state in order to force a
|
||||
* resend of the SETCLIENTID and hence re-establish the
|
||||
* callback channel. Then return all existing delegations.
|
||||
*/
|
||||
void nfs40_handle_cb_pathdown(struct nfs_client *clp)
|
||||
{
|
||||
set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
|
||||
nfs_expire_all_delegations(clp);
|
||||
dprintk("%s: handling CB_PATHDOWN recovery for server %s\n", __func__,
|
||||
clp->cl_hostname);
|
||||
}
|
||||
|
||||
void nfs4_schedule_path_down_recovery(struct nfs_client *clp)
|
||||
{
|
||||
nfs40_handle_cb_pathdown(clp);
|
||||
nfs4_schedule_state_manager(clp);
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs40_walk_client_list - Find server that recognizes a client ID
|
||||
*
|
||||
* @new: nfs_client with client ID to test
|
||||
* @result: OUT: found nfs_client, or new
|
||||
* @cred: credential to use for trunking test
|
||||
*
|
||||
* Returns zero, a negative errno, or a negative NFS4ERR status.
|
||||
* If zero is returned, an nfs_client pointer is planted in "result."
|
||||
*
|
||||
* NB: nfs40_walk_client_list() relies on the new nfs_client being
|
||||
* the last nfs_client on the list.
|
||||
*/
|
||||
static int nfs40_walk_client_list(struct nfs_client *new,
|
||||
struct nfs_client **result,
|
||||
const struct cred *cred)
|
||||
{
|
||||
struct nfs_net *nn = net_generic(new->cl_net, nfs_net_id);
|
||||
struct nfs_client *pos, *prev = NULL;
|
||||
struct nfs4_setclientid_res clid = {
|
||||
.clientid = new->cl_clientid,
|
||||
.confirm = new->cl_confirm,
|
||||
};
|
||||
int status = -NFS4ERR_STALE_CLIENTID;
|
||||
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
list_for_each_entry(pos, &nn->nfs_client_list, cl_share_link) {
|
||||
|
||||
if (pos == new)
|
||||
goto found;
|
||||
|
||||
status = nfs4_match_client(pos, new, &prev, nn);
|
||||
if (status < 0)
|
||||
goto out_unlock;
|
||||
if (status != 0)
|
||||
continue;
|
||||
/*
|
||||
* We just sent a new SETCLIENTID, which should have
|
||||
* caused the server to return a new cl_confirm. So if
|
||||
* cl_confirm is the same, then this is a different
|
||||
* server that just returned the same cl_confirm by
|
||||
* coincidence:
|
||||
*/
|
||||
if ((new != pos) && nfs4_same_verifier(&pos->cl_confirm,
|
||||
&new->cl_confirm))
|
||||
continue;
|
||||
/*
|
||||
* But if the cl_confirm's are different, then the only
|
||||
* way that a SETCLIENTID_CONFIRM to pos can succeed is
|
||||
* if new and pos point to the same server:
|
||||
*/
|
||||
found:
|
||||
refcount_inc(&pos->cl_count);
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
|
||||
nfs_put_client(prev);
|
||||
prev = pos;
|
||||
|
||||
status = nfs4_proc_setclientid_confirm(pos, &clid, cred);
|
||||
switch (status) {
|
||||
case -NFS4ERR_STALE_CLIENTID:
|
||||
break;
|
||||
case 0:
|
||||
nfs4_swap_callback_idents(pos, new);
|
||||
pos->cl_confirm = new->cl_confirm;
|
||||
nfs_mark_client_ready(pos, NFS_CS_READY);
|
||||
|
||||
prev = NULL;
|
||||
*result = pos;
|
||||
goto out;
|
||||
case -ERESTARTSYS:
|
||||
case -ETIMEDOUT:
|
||||
/* The callback path may have been inadvertently
|
||||
* changed. Schedule recovery!
|
||||
*/
|
||||
nfs4_schedule_path_down_recovery(pos);
|
||||
goto out;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock(&nn->nfs_client_lock);
|
||||
}
|
||||
out_unlock:
|
||||
spin_unlock(&nn->nfs_client_lock);
|
||||
|
||||
/* No match found. The server lost our clientid */
|
||||
out:
|
||||
nfs_put_client(prev);
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs40_discover_server_trunking - Detect server IP address trunking (mv0)
|
||||
*
|
||||
* @clp: nfs_client under test
|
||||
* @result: OUT: found nfs_client, or clp
|
||||
* @cred: credential to use for trunking test
|
||||
*
|
||||
* Returns zero, a negative errno, or a negative NFS4ERR status.
|
||||
* If zero is returned, an nfs_client pointer is planted in
|
||||
* "result".
|
||||
*
|
||||
* Note: The returned client may not yet be marked ready.
|
||||
*/
|
||||
int nfs40_discover_server_trunking(struct nfs_client *clp,
|
||||
struct nfs_client **result,
|
||||
const struct cred *cred)
|
||||
{
|
||||
struct nfs4_setclientid_res clid = {
|
||||
.clientid = clp->cl_clientid,
|
||||
.confirm = clp->cl_confirm,
|
||||
};
|
||||
struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
|
||||
unsigned short port;
|
||||
int status;
|
||||
|
||||
port = nn->nfs_callback_tcpport;
|
||||
if (clp->cl_addr.ss_family == AF_INET6)
|
||||
port = nn->nfs_callback_tcpport6;
|
||||
|
||||
status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
clp->cl_clientid = clid.clientid;
|
||||
clp->cl_confirm = clid.confirm;
|
||||
|
||||
status = nfs40_walk_client_list(clp, result, cred);
|
||||
if (status == 0) {
|
||||
/* Sustain the lease, even if it's empty. If the clientid4
|
||||
* goes stale it's of no use for trunking discovery. */
|
||||
nfs4_schedule_state_renewal(*result);
|
||||
|
||||
/* If the client state need to recover, do it. */
|
||||
if (clp->cl_state)
|
||||
nfs4_schedule_state_manager(clp);
|
||||
}
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
@@ -0,0 +1,395 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
#include <linux/nfs4.h>
|
||||
#include <linux/nfs.h>
|
||||
#include <linux/sunrpc/sched.h>
|
||||
#include <linux/nfs_fs.h>
|
||||
#include "internal.h"
|
||||
#include "nfs4_fs.h"
|
||||
#include "nfs40.h"
|
||||
#include "nfs4session.h"
|
||||
#include "nfs4trace.h"
|
||||
|
||||
static void nfs40_call_sync_prepare(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs4_call_sync_data *data = calldata;
|
||||
nfs4_setup_sequence(data->seq_server->nfs_client,
|
||||
data->seq_args, data->seq_res, task);
|
||||
}
|
||||
|
||||
static void nfs40_call_sync_done(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs4_call_sync_data *data = calldata;
|
||||
nfs4_sequence_done(task, data->seq_res);
|
||||
}
|
||||
|
||||
static void nfs40_sequence_free_slot(struct nfs4_sequence_res *res)
|
||||
{
|
||||
struct nfs4_slot *slot = res->sr_slot;
|
||||
struct nfs4_slot_table *tbl;
|
||||
|
||||
tbl = slot->table;
|
||||
spin_lock(&tbl->slot_tbl_lock);
|
||||
if (!nfs41_wake_and_assign_slot(tbl, slot))
|
||||
nfs4_free_slot(tbl, slot);
|
||||
spin_unlock(&tbl->slot_tbl_lock);
|
||||
|
||||
res->sr_slot = NULL;
|
||||
}
|
||||
|
||||
static int nfs40_sequence_done(struct rpc_task *task,
|
||||
struct nfs4_sequence_res *res)
|
||||
{
|
||||
if (res->sr_slot != NULL)
|
||||
nfs40_sequence_free_slot(res);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void nfs40_clear_delegation_stateid(struct nfs4_state *state)
|
||||
{
|
||||
if (rcu_access_pointer(NFS_I(state->inode)->delegation) != NULL)
|
||||
nfs_finish_clear_delegation_stateid(state, NULL);
|
||||
}
|
||||
|
||||
static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
|
||||
{
|
||||
/* NFSv4.0 doesn't allow for delegation recovery on open expire */
|
||||
nfs40_clear_delegation_stateid(state);
|
||||
nfs_state_clear_open_state_flags(state);
|
||||
return nfs4_open_expired(sp, state);
|
||||
}
|
||||
|
||||
struct nfs4_renewdata {
|
||||
struct nfs_client *client;
|
||||
unsigned long timestamp;
|
||||
};
|
||||
|
||||
/*
|
||||
* nfs4_proc_async_renew(): This is not one of the nfs_rpc_ops; it is a special
|
||||
* standalone procedure for queueing an asynchronous RENEW.
|
||||
*/
|
||||
static void nfs4_renew_release(void *calldata)
|
||||
{
|
||||
struct nfs4_renewdata *data = calldata;
|
||||
struct nfs_client *clp = data->client;
|
||||
|
||||
if (refcount_read(&clp->cl_count) > 1)
|
||||
nfs4_schedule_state_renewal(clp);
|
||||
nfs_put_client(clp);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static void nfs4_renew_done(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs4_renewdata *data = calldata;
|
||||
struct nfs_client *clp = data->client;
|
||||
unsigned long timestamp = data->timestamp;
|
||||
|
||||
trace_nfs4_renew_async(clp, task->tk_status);
|
||||
switch (task->tk_status) {
|
||||
case 0:
|
||||
break;
|
||||
case -NFS4ERR_LEASE_MOVED:
|
||||
nfs4_schedule_lease_moved_recovery(clp);
|
||||
break;
|
||||
default:
|
||||
/* Unless we're shutting down, schedule state recovery! */
|
||||
if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) == 0)
|
||||
return;
|
||||
if (task->tk_status != NFS4ERR_CB_PATH_DOWN) {
|
||||
nfs4_schedule_lease_recovery(clp);
|
||||
return;
|
||||
}
|
||||
nfs4_schedule_path_down_recovery(clp);
|
||||
}
|
||||
do_renew_lease(clp, timestamp);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfs4_renew_ops = {
|
||||
.rpc_call_done = nfs4_renew_done,
|
||||
.rpc_release = nfs4_renew_release,
|
||||
};
|
||||
|
||||
static int nfs4_proc_async_renew(struct nfs_client *clp, const struct cred *cred, unsigned renew_flags)
|
||||
{
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW],
|
||||
.rpc_argp = clp,
|
||||
.rpc_cred = cred,
|
||||
};
|
||||
struct nfs4_renewdata *data;
|
||||
|
||||
if (renew_flags == 0)
|
||||
return 0;
|
||||
if (!refcount_inc_not_zero(&clp->cl_count))
|
||||
return -EIO;
|
||||
data = kmalloc(sizeof(*data), GFP_NOFS);
|
||||
if (data == NULL) {
|
||||
nfs_put_client(clp);
|
||||
return -ENOMEM;
|
||||
}
|
||||
data->client = clp;
|
||||
data->timestamp = jiffies;
|
||||
return rpc_call_async(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT,
|
||||
&nfs4_renew_ops, data);
|
||||
}
|
||||
|
||||
static int nfs4_proc_renew(struct nfs_client *clp, const struct cred *cred)
|
||||
{
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENEW],
|
||||
.rpc_argp = clp,
|
||||
.rpc_cred = cred,
|
||||
};
|
||||
unsigned long now = jiffies;
|
||||
int status;
|
||||
|
||||
status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
|
||||
if (status < 0)
|
||||
return status;
|
||||
do_renew_lease(clp, now);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nfs40_test_and_free_expired_stateid(struct nfs_server *server,
|
||||
nfs4_stateid *stateid,
|
||||
const struct cred *cred)
|
||||
{
|
||||
return -NFS4ERR_BAD_STATEID;
|
||||
}
|
||||
|
||||
/*
|
||||
* This operation also signals the server that this client is
|
||||
* performing migration recovery. The server can stop returning
|
||||
* NFS4ERR_LEASE_MOVED to this client. A RENEW operation is
|
||||
* appended to this compound to identify the client ID which is
|
||||
* performing recovery.
|
||||
*/
|
||||
static int _nfs40_proc_get_locations(struct nfs_server *server,
|
||||
struct nfs_fh *fhandle,
|
||||
struct nfs4_fs_locations *locations,
|
||||
struct page *page, const struct cred *cred)
|
||||
{
|
||||
struct rpc_clnt *clnt = server->client;
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
u32 bitmask[2] = {
|
||||
[0] = FATTR4_WORD0_FSID | FATTR4_WORD0_FS_LOCATIONS,
|
||||
};
|
||||
struct nfs4_fs_locations_arg args = {
|
||||
.clientid = clp->cl_clientid,
|
||||
.fh = fhandle,
|
||||
.page = page,
|
||||
.bitmask = bitmask,
|
||||
.migration = 1, /* skip LOOKUP */
|
||||
.renew = 1, /* append RENEW */
|
||||
};
|
||||
struct nfs4_fs_locations_res res = {
|
||||
.fs_locations = locations,
|
||||
.migration = 1,
|
||||
.renew = 1,
|
||||
};
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FS_LOCATIONS],
|
||||
.rpc_argp = &args,
|
||||
.rpc_resp = &res,
|
||||
.rpc_cred = cred,
|
||||
};
|
||||
unsigned long now = jiffies;
|
||||
int status;
|
||||
|
||||
nfs_fattr_init(locations->fattr);
|
||||
locations->server = server;
|
||||
locations->nlocations = 0;
|
||||
|
||||
nfs4_init_sequence(clp, &args.seq_args, &res.seq_res, 0, 1);
|
||||
status = nfs4_call_sync_sequence(clnt, server, &msg,
|
||||
&args.seq_args, &res.seq_res);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
renew_lease(server, now);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This operation also signals the server that this client is
|
||||
* performing "lease moved" recovery. The server can stop
|
||||
* returning NFS4ERR_LEASE_MOVED to this client. A RENEW operation
|
||||
* is appended to this compound to identify the client ID which is
|
||||
* performing recovery.
|
||||
*/
|
||||
static int _nfs40_proc_fsid_present(struct inode *inode, const struct cred *cred)
|
||||
{
|
||||
struct nfs_server *server = NFS_SERVER(inode);
|
||||
struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
|
||||
struct rpc_clnt *clnt = server->client;
|
||||
struct nfs4_fsid_present_arg args = {
|
||||
.fh = NFS_FH(inode),
|
||||
.clientid = clp->cl_clientid,
|
||||
.renew = 1, /* append RENEW */
|
||||
};
|
||||
struct nfs4_fsid_present_res res = {
|
||||
.renew = 1,
|
||||
};
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FSID_PRESENT],
|
||||
.rpc_argp = &args,
|
||||
.rpc_resp = &res,
|
||||
.rpc_cred = cred,
|
||||
};
|
||||
unsigned long now = jiffies;
|
||||
int status;
|
||||
|
||||
res.fh = nfs_alloc_fhandle();
|
||||
if (res.fh == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
nfs4_init_sequence(clp, &args.seq_args, &res.seq_res, 0, 1);
|
||||
status = nfs4_call_sync_sequence(clnt, server, &msg,
|
||||
&args.seq_args, &res.seq_res);
|
||||
nfs_free_fhandle(res.fh);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
do_renew_lease(clp, now);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct nfs_release_lockowner_data {
|
||||
struct nfs4_lock_state *lsp;
|
||||
struct nfs_server *server;
|
||||
struct nfs_release_lockowner_args args;
|
||||
struct nfs_release_lockowner_res res;
|
||||
unsigned long timestamp;
|
||||
};
|
||||
|
||||
static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs_release_lockowner_data *data = calldata;
|
||||
struct nfs_server *server = data->server;
|
||||
nfs4_setup_sequence(server->nfs_client, &data->args.seq_args,
|
||||
&data->res.seq_res, task);
|
||||
data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
|
||||
data->timestamp = jiffies;
|
||||
}
|
||||
|
||||
static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs_release_lockowner_data *data = calldata;
|
||||
struct nfs_server *server = data->server;
|
||||
|
||||
nfs40_sequence_done(task, &data->res.seq_res);
|
||||
|
||||
switch (task->tk_status) {
|
||||
case 0:
|
||||
renew_lease(server, data->timestamp);
|
||||
break;
|
||||
case -NFS4ERR_STALE_CLIENTID:
|
||||
case -NFS4ERR_EXPIRED:
|
||||
nfs4_schedule_lease_recovery(server->nfs_client);
|
||||
break;
|
||||
case -NFS4ERR_LEASE_MOVED:
|
||||
case -NFS4ERR_DELAY:
|
||||
if (nfs4_async_handle_error(task, server,
|
||||
NULL, NULL) == -EAGAIN)
|
||||
rpc_restart_call_prepare(task);
|
||||
}
|
||||
}
|
||||
|
||||
static void nfs4_release_lockowner_release(void *calldata)
|
||||
{
|
||||
struct nfs_release_lockowner_data *data = calldata;
|
||||
nfs4_free_lock_state(data->server, data->lsp);
|
||||
kfree(calldata);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfs4_release_lockowner_ops = {
|
||||
.rpc_call_prepare = nfs4_release_lockowner_prepare,
|
||||
.rpc_call_done = nfs4_release_lockowner_done,
|
||||
.rpc_release = nfs4_release_lockowner_release,
|
||||
};
|
||||
|
||||
static void
|
||||
nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_state *lsp)
|
||||
{
|
||||
struct nfs_release_lockowner_data *data;
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
struct rpc_message msg = {
|
||||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER],
|
||||
};
|
||||
|
||||
if (clp->cl_mvops->minor_version != 0)
|
||||
return;
|
||||
|
||||
data = kmalloc(sizeof(*data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return;
|
||||
data->lsp = lsp;
|
||||
data->server = server;
|
||||
data->args.lock_owner.clientid = clp->cl_clientid;
|
||||
data->args.lock_owner.id = lsp->ls_seqid.owner_id;
|
||||
data->args.lock_owner.s_dev = server->s_dev;
|
||||
|
||||
msg.rpc_argp = &data->args;
|
||||
msg.rpc_resp = &data->res;
|
||||
nfs4_init_sequence(clp, &data->args.seq_args, &data->res.seq_res, 0, 0);
|
||||
rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfs40_call_sync_ops = {
|
||||
.rpc_call_prepare = nfs40_call_sync_prepare,
|
||||
.rpc_call_done = nfs40_call_sync_done,
|
||||
};
|
||||
|
||||
static const struct nfs4_sequence_slot_ops nfs40_sequence_slot_ops = {
|
||||
.process = nfs40_sequence_done,
|
||||
.done = nfs40_sequence_done,
|
||||
.free_slot = nfs40_sequence_free_slot,
|
||||
};
|
||||
|
||||
static const struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = {
|
||||
.owner_flag_bit = NFS_OWNER_RECLAIM_REBOOT,
|
||||
.state_flag_bit = NFS_STATE_RECLAIM_REBOOT,
|
||||
.recover_open = nfs4_open_reclaim,
|
||||
.recover_lock = nfs4_lock_reclaim,
|
||||
.establish_clid = nfs4_init_clientid,
|
||||
.detect_trunking = nfs40_discover_server_trunking,
|
||||
};
|
||||
|
||||
static const struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = {
|
||||
.owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE,
|
||||
.state_flag_bit = NFS_STATE_RECLAIM_NOGRACE,
|
||||
.recover_open = nfs40_open_expired,
|
||||
.recover_lock = nfs4_lock_expired,
|
||||
.establish_clid = nfs4_init_clientid,
|
||||
};
|
||||
|
||||
static const struct nfs4_state_maintenance_ops nfs40_state_renewal_ops = {
|
||||
.sched_state_renewal = nfs4_proc_async_renew,
|
||||
.get_state_renewal_cred = nfs4_get_renew_cred,
|
||||
.renew_lease = nfs4_proc_renew,
|
||||
};
|
||||
|
||||
static const struct nfs4_mig_recovery_ops nfs40_mig_recovery_ops = {
|
||||
.get_locations = _nfs40_proc_get_locations,
|
||||
.fsid_present = _nfs40_proc_fsid_present,
|
||||
};
|
||||
|
||||
const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
|
||||
.minor_version = 0,
|
||||
.init_caps = NFS_CAP_READDIRPLUS
|
||||
| NFS_CAP_ATOMIC_OPEN
|
||||
| NFS_CAP_POSIX_LOCK,
|
||||
.init_client = nfs40_init_client,
|
||||
.shutdown_client = nfs40_shutdown_client,
|
||||
.match_stateid = nfs4_match_stateid,
|
||||
.find_root_sec = nfs4_find_root_sec,
|
||||
.free_lock_state = nfs4_release_lockowner,
|
||||
.test_and_free_expired = nfs40_test_and_free_expired_stateid,
|
||||
.alloc_seqid = nfs_alloc_seqid,
|
||||
.call_sync_ops = &nfs40_call_sync_ops,
|
||||
.sequence_slot_ops = &nfs40_sequence_slot_ops,
|
||||
.reboot_recovery_ops = &nfs40_reboot_recovery_ops,
|
||||
.nograce_recovery_ops = &nfs40_nograce_recovery_ops,
|
||||
.state_renewal_ops = &nfs40_state_renewal_ops,
|
||||
.mig_recovery_ops = &nfs40_mig_recovery_ops,
|
||||
};
|
||||
+8
-5
@@ -670,8 +670,8 @@ static int nfs42_do_offload_cancel_async(struct file *dst,
|
||||
msg.rpc_argp = &data->args;
|
||||
msg.rpc_resp = &data->res;
|
||||
task_setup_data.callback_data = data;
|
||||
nfs4_init_sequence(&data->args.osa_seq_args, &data->res.osr_seq_res,
|
||||
1, 0);
|
||||
nfs4_init_sequence(dst_server->nfs_client, &data->args.osa_seq_args,
|
||||
&data->res.osr_seq_res, 1, 0);
|
||||
task = rpc_run_task(&task_setup_data);
|
||||
if (IS_ERR(task))
|
||||
return PTR_ERR(task);
|
||||
@@ -1072,7 +1072,8 @@ int nfs42_proc_layoutstats_generic(struct nfs_server *server,
|
||||
nfs42_layoutstat_release(data);
|
||||
return -EAGAIN;
|
||||
}
|
||||
nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0, 0);
|
||||
nfs4_init_sequence(server->nfs_client, &data->args.seq_args,
|
||||
&data->res.seq_res, 0, 0);
|
||||
task = rpc_run_task(&task_setup);
|
||||
if (IS_ERR(task))
|
||||
return PTR_ERR(task);
|
||||
@@ -1210,6 +1211,7 @@ int nfs42_proc_layouterror(struct pnfs_layout_segment *lseg,
|
||||
const struct nfs42_layout_error *errors, size_t n)
|
||||
{
|
||||
struct inode *inode = lseg->pls_layout->plh_inode;
|
||||
struct nfs_server *server = NFS_SERVER(inode);
|
||||
struct nfs42_layouterror_data *data;
|
||||
struct rpc_task *task;
|
||||
struct rpc_message msg = {
|
||||
@@ -1237,8 +1239,9 @@ int nfs42_proc_layouterror(struct pnfs_layout_segment *lseg,
|
||||
msg.rpc_argp = &data->args;
|
||||
msg.rpc_resp = &data->res;
|
||||
task_setup.callback_data = data;
|
||||
task_setup.rpc_client = NFS_SERVER(inode)->client;
|
||||
nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0, 0);
|
||||
task_setup.rpc_client = server->client;
|
||||
nfs4_init_sequence(server->nfs_client, &data->args.seq_args,
|
||||
&data->res.seq_res, 0, 0);
|
||||
task = rpc_run_task(&task_setup);
|
||||
if (IS_ERR(task))
|
||||
return PTR_ERR(task);
|
||||
|
||||
+46
-40
@@ -10,12 +10,16 @@
|
||||
#ifndef __LINUX_FS_NFS_NFS4_FS_H
|
||||
#define __LINUX_FS_NFS_NFS4_FS_H
|
||||
|
||||
#if defined(CONFIG_NFS_V4_0)
|
||||
#define NFS4_MIN_MINOR_VERSION 0
|
||||
#else
|
||||
#define NFS4_MIN_MINOR_VERSION 1
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_NFS_V4_2)
|
||||
#define NFS4_MAX_MINOR_VERSION 2
|
||||
#elif defined(CONFIG_NFS_V4_1)
|
||||
#define NFS4_MAX_MINOR_VERSION 1
|
||||
#else
|
||||
#define NFS4_MAX_MINOR_VERSION 0
|
||||
#define NFS4_MAX_MINOR_VERSION 1
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_NFS_V4)
|
||||
@@ -73,6 +77,7 @@ struct nfs4_minor_version_ops {
|
||||
void (*session_trunk)(struct rpc_clnt *clnt,
|
||||
struct rpc_xprt *xprt, void *data);
|
||||
const struct rpc_call_ops *call_sync_ops;
|
||||
const struct nfs4_sequence_slot_ops *sequence_slot_ops;
|
||||
const struct nfs4_state_recovery_ops *reboot_recovery_ops;
|
||||
const struct nfs4_state_recovery_ops *nograce_recovery_ops;
|
||||
const struct nfs4_state_maintenance_ops *state_renewal_ops;
|
||||
@@ -256,6 +261,12 @@ struct nfs4_add_xprt_data {
|
||||
const struct cred *cred;
|
||||
};
|
||||
|
||||
struct nfs4_sequence_slot_ops {
|
||||
int (*process)(struct rpc_task *, struct nfs4_sequence_res *);
|
||||
int (*done)(struct rpc_task *, struct nfs4_sequence_res *);
|
||||
void (*free_slot)(struct nfs4_sequence_res *);
|
||||
};
|
||||
|
||||
struct nfs4_state_maintenance_ops {
|
||||
int (*sched_state_renewal)(struct nfs_client *, const struct cred *, unsigned);
|
||||
const struct cred * (*get_state_renewal_cred)(struct nfs_client *);
|
||||
@@ -277,6 +288,11 @@ int nfs_atomic_open(struct inode *, struct dentry *, struct file *,
|
||||
/* fs_context.c */
|
||||
extern struct file_system_type nfs4_fs_type;
|
||||
|
||||
/* nfs4client.c */
|
||||
struct nfs_net;
|
||||
int nfs4_match_client(struct nfs_client *pos, struct nfs_client *new,
|
||||
struct nfs_client **prev, struct nfs_net *nn);
|
||||
|
||||
/* nfs4namespace.c */
|
||||
struct rpc_clnt *nfs4_negotiate_security(struct rpc_clnt *, struct inode *,
|
||||
const struct qstr *);
|
||||
@@ -286,6 +302,12 @@ int nfs4_replace_transport(struct nfs_server *server,
|
||||
size_t nfs_parse_server_name(char *string, size_t len, struct sockaddr_storage *ss,
|
||||
size_t salen, struct net *net, int port);
|
||||
/* nfs4proc.c */
|
||||
struct nfs4_call_sync_data {
|
||||
const struct nfs_server *seq_server;
|
||||
struct nfs4_sequence_args *seq_args;
|
||||
struct nfs4_sequence_res *seq_res;
|
||||
};
|
||||
|
||||
extern int nfs4_handle_exception(struct nfs_server *, int, struct nfs4_exception *);
|
||||
extern int nfs4_async_handle_error(struct rpc_task *task,
|
||||
struct nfs_server *server,
|
||||
@@ -293,9 +315,16 @@ extern int nfs4_async_handle_error(struct rpc_task *task,
|
||||
extern int nfs4_call_sync(struct rpc_clnt *, struct nfs_server *,
|
||||
struct rpc_message *, struct nfs4_sequence_args *,
|
||||
struct nfs4_sequence_res *, int);
|
||||
extern void nfs4_init_sequence(struct nfs4_sequence_args *, struct nfs4_sequence_res *, int, int);
|
||||
extern int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
|
||||
struct nfs_server *server,
|
||||
struct rpc_message *msg,
|
||||
struct nfs4_sequence_args *args,
|
||||
struct nfs4_sequence_res *res);
|
||||
extern void nfs4_init_sequence(struct nfs_client *clp, struct nfs4_sequence_args *,
|
||||
struct nfs4_sequence_res *, int, int);
|
||||
extern int nfs4_proc_setclientid(struct nfs_client *, u32, unsigned short, const struct cred *, struct nfs4_setclientid_res *);
|
||||
extern int nfs4_proc_setclientid_confirm(struct nfs_client *, struct nfs4_setclientid_res *arg, const struct cred *);
|
||||
extern void renew_lease(const struct nfs_server *server, unsigned long timestamp);
|
||||
extern int nfs4_proc_get_rootfh(struct nfs_server *, struct nfs_fh *,
|
||||
struct nfs_fattr *, bool);
|
||||
extern int nfs4_proc_bind_conn_to_session(struct nfs_client *, const struct cred *cred);
|
||||
@@ -339,8 +368,19 @@ extern void nfs4_update_changeattr(struct inode *dir,
|
||||
unsigned long cache_validity);
|
||||
extern int nfs4_buf_to_pages_noslab(const void *buf, size_t buflen,
|
||||
struct page **pages);
|
||||
extern int nfs4_open_reclaim(struct nfs4_state_owner *, struct nfs4_state *);
|
||||
extern int nfs4_open_expired(struct nfs4_state_owner *, struct nfs4_state *);
|
||||
extern int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request);
|
||||
extern int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request);
|
||||
extern void nfs_state_clear_delegation(struct nfs4_state *state);
|
||||
extern void nfs_finish_clear_delegation_stateid(struct nfs4_state *state,
|
||||
const nfs4_stateid *stateid);
|
||||
extern void nfs_state_clear_open_state_flags(struct nfs4_state *state);
|
||||
extern void do_renew_lease(struct nfs_client *clp, unsigned long timestamp);
|
||||
extern bool nfs4_match_stateid(const nfs4_stateid *s1, const nfs4_stateid *s2);
|
||||
extern int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
struct nfs_fattr *fattr);
|
||||
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
extern int nfs41_sequence_done(struct rpc_task *, struct nfs4_sequence_res *);
|
||||
extern int nfs4_proc_create_session(struct nfs_client *, const struct cred *);
|
||||
extern int nfs4_proc_destroy_session(struct nfs4_session *, const struct cred *);
|
||||
@@ -418,31 +458,6 @@ nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp,
|
||||
!test_bit(NFS_SP4_MACH_CRED_COMMIT, &clp->cl_sp4_flags))
|
||||
hdr->args.stable = NFS_FILE_SYNC;
|
||||
}
|
||||
#else /* CONFIG_NFS_v4_1 */
|
||||
static inline bool
|
||||
is_ds_only_client(struct nfs_client *clp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
is_ds_client(struct nfs_client *clp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void
|
||||
nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_flags,
|
||||
struct rpc_clnt **clntp, struct rpc_message *msg)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void
|
||||
nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp,
|
||||
struct rpc_message *msg, struct nfs_pgio_header *hdr)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
||||
extern const struct nfs4_minor_version_ops *nfs_v4_minor_ops[];
|
||||
|
||||
@@ -452,9 +467,7 @@ extern const u32 nfs4_pathconf_bitmap[3];
|
||||
extern const u32 nfs4_fsinfo_bitmap[3];
|
||||
extern const u32 nfs4_fs_locations_bitmap[3];
|
||||
|
||||
void nfs40_shutdown_client(struct nfs_client *);
|
||||
void nfs41_shutdown_client(struct nfs_client *);
|
||||
int nfs40_init_client(struct nfs_client *);
|
||||
int nfs41_init_client(struct nfs_client *);
|
||||
void nfs4_free_client(struct nfs_client *);
|
||||
|
||||
@@ -464,8 +477,7 @@ struct nfs_client *nfs4_alloc_client(const struct nfs_client_initdata *);
|
||||
extern void nfs4_schedule_state_renewal(struct nfs_client *);
|
||||
extern void nfs4_kill_renewd(struct nfs_client *);
|
||||
extern void nfs4_renew_state(struct work_struct *);
|
||||
extern void nfs4_set_lease_period(struct nfs_client *clp, unsigned long lease);
|
||||
|
||||
extern void nfs4_set_lease_period(struct nfs_client *clp, u32 period);
|
||||
|
||||
/* nfs4state.c */
|
||||
extern const nfs4_stateid current_stateid;
|
||||
@@ -477,18 +489,12 @@ int nfs4_discover_server_trunking(struct nfs_client *clp,
|
||||
struct nfs_client **);
|
||||
int nfs40_discover_server_trunking(struct nfs_client *clp,
|
||||
struct nfs_client **, const struct cred *);
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
int nfs41_discover_server_trunking(struct nfs_client *clp,
|
||||
struct nfs_client **, const struct cred *);
|
||||
extern void nfs4_schedule_session_recovery(struct nfs4_session *, int);
|
||||
extern void nfs41_notify_server(struct nfs_client *);
|
||||
bool nfs4_check_serverowner_major_id(struct nfs41_server_owner *o1,
|
||||
struct nfs41_server_owner *o2);
|
||||
#else
|
||||
static inline void nfs4_schedule_session_recovery(struct nfs4_session *session, int err)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
||||
extern struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *, const struct cred *, gfp_t);
|
||||
extern void nfs4_put_state_owner(struct nfs4_state_owner *);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user