Merge tag 'nfs-for-4.4-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust:
"Highlights include:
New features:
- RDMA client backchannel from Chuck
- Support for NFSv4.2 file CLONE using the btrfs ioctl
Bugfixes + cleanups:
- Move socket data receive out of the bottom halves and into a
workqueue
- Refactor NFSv4 error handling so synchronous and asynchronous RPC
handles errors identically.
- Fix a panic when blocks or object layouts reads return a bad data
length
- Fix nfsroot so it can handle a 1024 byte long path.
- Fix bad usage of page offset in bl_read_pagelist
- Various NFSv4 callback cleanups+fixes
- Fix GETATTR bitmap verification
- Support hexadecimal number for sunrpc debug sysctl files"
* tag 'nfs-for-4.4-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (53 commits)
Sunrpc: Supports hexadecimal number for sysctl files of sunrpc debug
nfs: Fix GETATTR bitmap verification
nfs: Remove unused xdr page offsets in getacl/setacl arguments
fs/nfs: remove unnecessary new_valid_dev check
SUNRPC: fix variable type
NFS: Enable client side NFSv4.1 backchannel to use other transports
pNFS/flexfiles: Add support for FF_FLAGS_NO_IO_THRU_MDS
pNFS/flexfiles: When mirrored, retry failed reads by switching mirrors
SUNRPC: Remove the TCP-only restriction in bc_svc_process()
svcrdma: Add backward direction service for RPC/RDMA transport
xprtrdma: Handle incoming backward direction RPC calls
xprtrdma: Add support for sending backward direction RPC replies
xprtrdma: Pre-allocate Work Requests for backchannel
xprtrdma: Pre-allocate backward rpc_rqst and send/receive buffers
SUNRPC: Abstract backchannel operations
xprtrdma: Saving IRQs no longer needed for rb_lock
xprtrdma: Remove reply tasklet
xprtrdma: Use workqueue to process RPC/RDMA replies
xprtrdma: Replace send and receive arrays
xprtrdma: Refactor reply handler error handling
...
This commit is contained in:
@@ -78,7 +78,6 @@ struct nfs4_opendata;
|
||||
static int _nfs4_proc_open(struct nfs4_opendata *data);
|
||||
static int _nfs4_recover_proc_open(struct nfs4_opendata *data);
|
||||
static int nfs4_do_fsinfo(struct nfs_server *, struct nfs_fh *, struct nfs_fsinfo *);
|
||||
static int nfs4_async_handle_error(struct rpc_task *, const struct nfs_server *, struct nfs4_state *, long *);
|
||||
static void nfs_fixup_referral_attributes(struct nfs_fattr *fattr);
|
||||
static int nfs4_proc_getattr(struct nfs_server *, struct nfs_fh *, struct nfs_fattr *, struct nfs4_label *label);
|
||||
static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr, struct nfs4_label *label);
|
||||
@@ -239,6 +238,7 @@ const u32 nfs4_fsinfo_bitmap[3] = { FATTR4_WORD0_MAXFILESIZE
|
||||
FATTR4_WORD1_TIME_DELTA
|
||||
| FATTR4_WORD1_FS_LAYOUT_TYPES,
|
||||
FATTR4_WORD2_LAYOUT_BLKSIZE
|
||||
| FATTR4_WORD2_CLONE_BLKSIZE
|
||||
};
|
||||
|
||||
const u32 nfs4_fs_locations_bitmap[3] = {
|
||||
@@ -344,13 +344,16 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
|
||||
/* This is the error handling routine for processes that are allowed
|
||||
* to sleep.
|
||||
*/
|
||||
int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
|
||||
static int nfs4_do_handle_exception(struct nfs_server *server,
|
||||
int errorcode, struct nfs4_exception *exception)
|
||||
{
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
struct nfs4_state *state = exception->state;
|
||||
struct inode *inode = exception->inode;
|
||||
int ret = errorcode;
|
||||
|
||||
exception->delay = 0;
|
||||
exception->recovering = 0;
|
||||
exception->retry = 0;
|
||||
switch(errorcode) {
|
||||
case 0:
|
||||
@@ -359,11 +362,9 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_
|
||||
case -NFS4ERR_DELEG_REVOKED:
|
||||
case -NFS4ERR_ADMIN_REVOKED:
|
||||
case -NFS4ERR_BAD_STATEID:
|
||||
if (inode && nfs4_have_delegation(inode, FMODE_READ)) {
|
||||
nfs4_inode_return_delegation(inode);
|
||||
exception->retry = 1;
|
||||
return 0;
|
||||
}
|
||||
if (inode && nfs_async_inode_return_delegation(inode,
|
||||
NULL) == 0)
|
||||
goto wait_on_recovery;
|
||||
if (state == NULL)
|
||||
break;
|
||||
ret = nfs4_schedule_stateid_recovery(server, state);
|
||||
@@ -409,11 +410,12 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
}
|
||||
case -NFS4ERR_GRACE:
|
||||
case -NFS4ERR_DELAY:
|
||||
ret = nfs4_delay(server->client, &exception->timeout);
|
||||
if (ret != 0)
|
||||
break;
|
||||
nfs_inc_server_stats(server, NFSIOS_DELAY);
|
||||
case -NFS4ERR_GRACE:
|
||||
exception->delay = 1;
|
||||
return 0;
|
||||
|
||||
case -NFS4ERR_RETRY_UNCACHED_REP:
|
||||
case -NFS4ERR_OLD_STATEID:
|
||||
exception->retry = 1;
|
||||
@@ -434,14 +436,85 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_
|
||||
/* We failed to handle the error */
|
||||
return nfs4_map_errors(ret);
|
||||
wait_on_recovery:
|
||||
ret = nfs4_wait_clnt_recover(clp);
|
||||
if (test_bit(NFS_MIG_FAILED, &server->mig_status))
|
||||
return -EIO;
|
||||
exception->recovering = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is the error handling routine for processes that are allowed
|
||||
* to sleep.
|
||||
*/
|
||||
int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
|
||||
{
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
int ret;
|
||||
|
||||
ret = nfs4_do_handle_exception(server, errorcode, exception);
|
||||
if (exception->delay) {
|
||||
ret = nfs4_delay(server->client, &exception->timeout);
|
||||
goto out_retry;
|
||||
}
|
||||
if (exception->recovering) {
|
||||
ret = nfs4_wait_clnt_recover(clp);
|
||||
if (test_bit(NFS_MIG_FAILED, &server->mig_status))
|
||||
return -EIO;
|
||||
goto out_retry;
|
||||
}
|
||||
return ret;
|
||||
out_retry:
|
||||
if (ret == 0)
|
||||
exception->retry = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nfs4_async_handle_exception(struct rpc_task *task, struct nfs_server *server,
|
||||
int errorcode, struct nfs4_exception *exception)
|
||||
{
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
int ret;
|
||||
|
||||
ret = nfs4_do_handle_exception(server, errorcode, exception);
|
||||
if (exception->delay) {
|
||||
rpc_delay(task, nfs4_update_delay(&exception->timeout));
|
||||
goto out_retry;
|
||||
}
|
||||
if (exception->recovering) {
|
||||
rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL);
|
||||
if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
|
||||
rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task);
|
||||
goto out_retry;
|
||||
}
|
||||
if (test_bit(NFS_MIG_FAILED, &server->mig_status))
|
||||
ret = -EIO;
|
||||
return ret;
|
||||
out_retry:
|
||||
if (ret == 0)
|
||||
exception->retry = 1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
nfs4_async_handle_error(struct rpc_task *task, struct nfs_server *server,
|
||||
struct nfs4_state *state, long *timeout)
|
||||
{
|
||||
struct nfs4_exception exception = {
|
||||
.state = state,
|
||||
};
|
||||
|
||||
if (task->tk_status >= 0)
|
||||
return 0;
|
||||
if (timeout)
|
||||
exception.timeout = *timeout;
|
||||
task->tk_status = nfs4_async_handle_exception(task, server,
|
||||
task->tk_status,
|
||||
&exception);
|
||||
if (exception.delay && timeout)
|
||||
*timeout = exception.timeout;
|
||||
if (exception.retry)
|
||||
return -EAGAIN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 'true' if 'clp' is using an rpc_client that is integrity protected
|
||||
* or 'false' otherwise.
|
||||
@@ -4530,7 +4603,7 @@ static inline int nfs4_server_supports_acls(struct nfs_server *server)
|
||||
#define NFS4ACL_MAXPAGES DIV_ROUND_UP(XATTR_SIZE_MAX, PAGE_SIZE)
|
||||
|
||||
static int buf_to_pages_noslab(const void *buf, size_t buflen,
|
||||
struct page **pages, unsigned int *pgbase)
|
||||
struct page **pages)
|
||||
{
|
||||
struct page *newpage, **spages;
|
||||
int rc = 0;
|
||||
@@ -4674,7 +4747,6 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
|
||||
goto out_free;
|
||||
|
||||
args.acl_len = npages * PAGE_SIZE;
|
||||
args.acl_pgbase = 0;
|
||||
|
||||
dprintk("%s buf %p buflen %zu npages %d args.acl_len %zu\n",
|
||||
__func__, buf, buflen, npages, args.acl_len);
|
||||
@@ -4766,7 +4838,7 @@ static int __nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t bufl
|
||||
return -EOPNOTSUPP;
|
||||
if (npages > ARRAY_SIZE(pages))
|
||||
return -ERANGE;
|
||||
i = buf_to_pages_noslab(buf, buflen, arg.acl_pages, &arg.acl_pgbase);
|
||||
i = buf_to_pages_noslab(buf, buflen, arg.acl_pages);
|
||||
if (i < 0)
|
||||
return i;
|
||||
nfs4_inode_return_delegation(inode);
|
||||
@@ -4955,79 +5027,6 @@ out:
|
||||
#endif /* CONFIG_NFS_V4_SECURITY_LABEL */
|
||||
|
||||
|
||||
static int
|
||||
nfs4_async_handle_error(struct rpc_task *task, const struct nfs_server *server,
|
||||
struct nfs4_state *state, long *timeout)
|
||||
{
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
|
||||
if (task->tk_status >= 0)
|
||||
return 0;
|
||||
switch(task->tk_status) {
|
||||
case -NFS4ERR_DELEG_REVOKED:
|
||||
case -NFS4ERR_ADMIN_REVOKED:
|
||||
case -NFS4ERR_BAD_STATEID:
|
||||
case -NFS4ERR_OPENMODE:
|
||||
if (state == NULL)
|
||||
break;
|
||||
if (nfs4_schedule_stateid_recovery(server, state) < 0)
|
||||
goto recovery_failed;
|
||||
goto wait_on_recovery;
|
||||
case -NFS4ERR_EXPIRED:
|
||||
if (state != NULL) {
|
||||
if (nfs4_schedule_stateid_recovery(server, state) < 0)
|
||||
goto recovery_failed;
|
||||
}
|
||||
case -NFS4ERR_STALE_STATEID:
|
||||
case -NFS4ERR_STALE_CLIENTID:
|
||||
nfs4_schedule_lease_recovery(clp);
|
||||
goto wait_on_recovery;
|
||||
case -NFS4ERR_MOVED:
|
||||
if (nfs4_schedule_migration_recovery(server) < 0)
|
||||
goto recovery_failed;
|
||||
goto wait_on_recovery;
|
||||
case -NFS4ERR_LEASE_MOVED:
|
||||
nfs4_schedule_lease_moved_recovery(clp);
|
||||
goto wait_on_recovery;
|
||||
#if defined(CONFIG_NFS_V4_1)
|
||||
case -NFS4ERR_BADSESSION:
|
||||
case -NFS4ERR_BADSLOT:
|
||||
case -NFS4ERR_BAD_HIGH_SLOT:
|
||||
case -NFS4ERR_DEADSESSION:
|
||||
case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
|
||||
case -NFS4ERR_SEQ_FALSE_RETRY:
|
||||
case -NFS4ERR_SEQ_MISORDERED:
|
||||
dprintk("%s ERROR %d, Reset session\n", __func__,
|
||||
task->tk_status);
|
||||
nfs4_schedule_session_recovery(clp->cl_session, task->tk_status);
|
||||
goto wait_on_recovery;
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
case -NFS4ERR_DELAY:
|
||||
nfs_inc_server_stats(server, NFSIOS_DELAY);
|
||||
rpc_delay(task, nfs4_update_delay(timeout));
|
||||
goto restart_call;
|
||||
case -NFS4ERR_GRACE:
|
||||
rpc_delay(task, NFS4_POLL_RETRY_MAX);
|
||||
case -NFS4ERR_RETRY_UNCACHED_REP:
|
||||
case -NFS4ERR_OLD_STATEID:
|
||||
goto restart_call;
|
||||
}
|
||||
task->tk_status = nfs4_map_errors(task->tk_status);
|
||||
return 0;
|
||||
recovery_failed:
|
||||
task->tk_status = -EIO;
|
||||
return 0;
|
||||
wait_on_recovery:
|
||||
rpc_sleep_on(&clp->cl_rpcwaitq, task, NULL);
|
||||
if (test_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) == 0)
|
||||
rpc_wake_up_queued_task(&clp->cl_rpcwaitq, task);
|
||||
if (test_bit(NFS_MIG_FAILED, &server->mig_status))
|
||||
goto recovery_failed;
|
||||
restart_call:
|
||||
task->tk_status = 0;
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static void nfs4_init_boot_verifier(const struct nfs_client *clp,
|
||||
nfs4_verifier *bootverf)
|
||||
{
|
||||
@@ -5522,7 +5521,7 @@ struct nfs4_unlockdata {
|
||||
struct nfs4_lock_state *lsp;
|
||||
struct nfs_open_context *ctx;
|
||||
struct file_lock fl;
|
||||
const struct nfs_server *server;
|
||||
struct nfs_server *server;
|
||||
unsigned long timestamp;
|
||||
};
|
||||
|
||||
@@ -8718,7 +8717,8 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
|
||||
| NFS_CAP_ALLOCATE
|
||||
| NFS_CAP_DEALLOCATE
|
||||
| NFS_CAP_SEEK
|
||||
| NFS_CAP_LAYOUTSTATS,
|
||||
| NFS_CAP_LAYOUTSTATS
|
||||
| NFS_CAP_CLONE,
|
||||
.init_client = nfs41_init_client,
|
||||
.shutdown_client = nfs41_shutdown_client,
|
||||
.match_stateid = nfs41_match_stateid,
|
||||
|
||||
Reference in New Issue
Block a user