Commit 0688e64b authored by Trond Myklebust's avatar Trond Myklebust Committed by Anna Schumaker

NFS: Allow signal interruption of NFS4ERR_DELAYed operations

If the server is unable to immediately execute an RPC call, and returns
an NFS4ERR_DELAY then we can assume it is safe to interrupt the operation
in order to handle ordinary signals. This allows the application to
service timer interrupts that would otherwise have to wait until the
server is again able to respond.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent 33344e0f
...@@ -206,6 +206,7 @@ struct nfs4_exception { ...@@ -206,6 +206,7 @@ struct nfs4_exception {
unsigned char delay : 1, unsigned char delay : 1,
recovering : 1, recovering : 1,
retry : 1; retry : 1;
bool interruptible;
}; };
struct nfs4_state_recovery_ops { struct nfs4_state_recovery_ops {
......
...@@ -400,17 +400,32 @@ static long nfs4_update_delay(long *timeout) ...@@ -400,17 +400,32 @@ static long nfs4_update_delay(long *timeout)
return ret; return ret;
} }
static int nfs4_delay(struct rpc_clnt *clnt, long *timeout) static int nfs4_delay_killable(long *timeout)
{ {
int res = 0;
might_sleep(); might_sleep();
freezable_schedule_timeout_killable_unsafe( freezable_schedule_timeout_killable_unsafe(
nfs4_update_delay(timeout)); nfs4_update_delay(timeout));
if (fatal_signal_pending(current)) if (!__fatal_signal_pending(current))
res = -ERESTARTSYS; return 0;
return res; return -EINTR;
}
static int nfs4_delay_interruptible(long *timeout)
{
might_sleep();
freezable_schedule_timeout_interruptible(nfs4_update_delay(timeout));
if (!signal_pending(current))
return 0;
return __fatal_signal_pending(current) ? -EINTR :-ERESTARTSYS;
}
static int nfs4_delay(long *timeout, bool interruptible)
{
if (interruptible)
return nfs4_delay_interruptible(timeout);
return nfs4_delay_killable(timeout);
} }
/* This is the error handling routine for processes that are allowed /* This is the error handling routine for processes that are allowed
...@@ -546,7 +561,8 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_ ...@@ -546,7 +561,8 @@ int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_
ret = nfs4_do_handle_exception(server, errorcode, exception); ret = nfs4_do_handle_exception(server, errorcode, exception);
if (exception->delay) { if (exception->delay) {
ret = nfs4_delay(server->client, &exception->timeout); ret = nfs4_delay(&exception->timeout,
exception->interruptible);
goto out_retry; goto out_retry;
} }
if (exception->recovering) { if (exception->recovering) {
...@@ -3066,7 +3082,9 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir, ...@@ -3066,7 +3082,9 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
int *opened) int *opened)
{ {
struct nfs_server *server = NFS_SERVER(dir); struct nfs_server *server = NFS_SERVER(dir);
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
struct nfs4_state *res; struct nfs4_state *res;
struct nfs4_open_createattrs c = { struct nfs4_open_createattrs c = {
.label = label, .label = label,
...@@ -3679,7 +3697,9 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f ...@@ -3679,7 +3697,9 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
do { do {
err = nfs4_handle_exception(server, err = nfs4_handle_exception(server,
...@@ -3721,7 +3741,9 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -3721,7 +3741,9 @@ static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info) struct nfs_fsinfo *info)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
do { do {
err = _nfs4_lookup_root(server, fhandle, info); err = _nfs4_lookup_root(server, fhandle, info);
...@@ -3948,7 +3970,9 @@ static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -3948,7 +3970,9 @@ static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fattr *fattr, struct nfs4_label *label, struct nfs_fattr *fattr, struct nfs4_label *label,
struct inode *inode) struct inode *inode)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
do { do {
err = _nfs4_proc_getattr(server, fhandle, fattr, label, inode); err = _nfs4_proc_getattr(server, fhandle, fattr, label, inode);
...@@ -4071,7 +4095,9 @@ static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir, ...@@ -4071,7 +4095,9 @@ static int nfs4_proc_lookup_common(struct rpc_clnt **clnt, struct inode *dir,
const struct qstr *name, struct nfs_fh *fhandle, const struct qstr *name, struct nfs_fh *fhandle,
struct nfs_fattr *fattr, struct nfs4_label *label) struct nfs_fattr *fattr, struct nfs4_label *label)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
struct rpc_clnt *client = *clnt; struct rpc_clnt *client = *clnt;
int err; int err;
do { do {
...@@ -4175,7 +4201,9 @@ static int _nfs4_proc_lookupp(struct inode *inode, ...@@ -4175,7 +4201,9 @@ static int _nfs4_proc_lookupp(struct inode *inode,
static int nfs4_proc_lookupp(struct inode *inode, struct nfs_fh *fhandle, static int nfs4_proc_lookupp(struct inode *inode, struct nfs_fh *fhandle,
struct nfs_fattr *fattr, struct nfs4_label *label) struct nfs_fattr *fattr, struct nfs4_label *label)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
do { do {
err = _nfs4_proc_lookupp(inode, fhandle, fattr, label); err = _nfs4_proc_lookupp(inode, fhandle, fattr, label);
...@@ -4222,7 +4250,9 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry ...@@ -4222,7 +4250,9 @@ static int _nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry
static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
do { do {
err = _nfs4_proc_access(inode, entry); err = _nfs4_proc_access(inode, entry);
...@@ -4277,7 +4307,9 @@ static int _nfs4_proc_readlink(struct inode *inode, struct page *page, ...@@ -4277,7 +4307,9 @@ static int _nfs4_proc_readlink(struct inode *inode, struct page *page,
static int nfs4_proc_readlink(struct inode *inode, struct page *page, static int nfs4_proc_readlink(struct inode *inode, struct page *page,
unsigned int pgbase, unsigned int pglen) unsigned int pgbase, unsigned int pglen)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
do { do {
err = _nfs4_proc_readlink(inode, page, pgbase, pglen); err = _nfs4_proc_readlink(inode, page, pgbase, pglen);
...@@ -4353,7 +4385,9 @@ _nfs4_proc_remove(struct inode *dir, const struct qstr *name, u32 ftype) ...@@ -4353,7 +4385,9 @@ _nfs4_proc_remove(struct inode *dir, const struct qstr *name, u32 ftype)
static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry) static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
struct inode *inode = d_inode(dentry); struct inode *inode = d_inode(dentry);
int err; int err;
...@@ -4374,7 +4408,9 @@ static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry) ...@@ -4374,7 +4408,9 @@ static int nfs4_proc_remove(struct inode *dir, struct dentry *dentry)
static int nfs4_proc_rmdir(struct inode *dir, const struct qstr *name) static int nfs4_proc_rmdir(struct inode *dir, const struct qstr *name)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
do { do {
...@@ -4533,7 +4569,9 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, const struct ...@@ -4533,7 +4569,9 @@ static int _nfs4_proc_link(struct inode *inode, struct inode *dir, const struct
static int nfs4_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name) static int nfs4_proc_link(struct inode *inode, struct inode *dir, const struct qstr *name)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
do { do {
err = nfs4_handle_exception(NFS_SERVER(inode), err = nfs4_handle_exception(NFS_SERVER(inode),
...@@ -4640,7 +4678,9 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, ...@@ -4640,7 +4678,9 @@ static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
struct page *page, unsigned int len, struct iattr *sattr) struct page *page, unsigned int len, struct iattr *sattr)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
struct nfs4_label l, *label = NULL; struct nfs4_label l, *label = NULL;
int err; int err;
...@@ -4679,7 +4719,9 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, ...@@ -4679,7 +4719,9 @@ static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
struct iattr *sattr) struct iattr *sattr)
{ {
struct nfs_server *server = NFS_SERVER(dir); struct nfs_server *server = NFS_SERVER(dir);
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
struct nfs4_label l, *label = NULL; struct nfs4_label l, *label = NULL;
int err; int err;
...@@ -4739,7 +4781,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, const struct cred *cred, ...@@ -4739,7 +4781,9 @@ static int _nfs4_proc_readdir(struct dentry *dentry, const struct cred *cred,
static int nfs4_proc_readdir(struct dentry *dentry, const struct cred *cred, static int nfs4_proc_readdir(struct dentry *dentry, const struct cred *cred,
u64 cookie, struct page **pages, unsigned int count, bool plus) u64 cookie, struct page **pages, unsigned int count, bool plus)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
do { do {
err = _nfs4_proc_readdir(dentry, cred, cookie, err = _nfs4_proc_readdir(dentry, cred, cookie,
...@@ -4790,7 +4834,9 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, ...@@ -4790,7 +4834,9 @@ static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
struct iattr *sattr, dev_t rdev) struct iattr *sattr, dev_t rdev)
{ {
struct nfs_server *server = NFS_SERVER(dir); struct nfs_server *server = NFS_SERVER(dir);
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
struct nfs4_label l, *label = NULL; struct nfs4_label l, *label = NULL;
int err; int err;
...@@ -4832,7 +4878,9 @@ static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -4832,7 +4878,9 @@ static int _nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
do { do {
err = nfs4_handle_exception(server, err = nfs4_handle_exception(server,
...@@ -4863,7 +4911,9 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -4863,7 +4911,9 @@ static int _nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle,
static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
unsigned long now = jiffies; unsigned long now = jiffies;
int err; int err;
...@@ -4925,7 +4975,9 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle ...@@ -4925,7 +4975,9 @@ static int _nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle
static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_pathconf *pathconf) struct nfs_pathconf *pathconf)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
do { do {
...@@ -5494,7 +5546,9 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu ...@@ -5494,7 +5546,9 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
ssize_t ret; ssize_t ret;
do { do {
ret = __nfs4_get_acl_uncached(inode, buf, buflen); ret = __nfs4_get_acl_uncached(inode, buf, buflen);
...@@ -5628,7 +5682,9 @@ static int _nfs4_get_security_label(struct inode *inode, void *buf, ...@@ -5628,7 +5682,9 @@ static int _nfs4_get_security_label(struct inode *inode, void *buf,
static int nfs4_get_security_label(struct inode *inode, void *buf, static int nfs4_get_security_label(struct inode *inode, void *buf,
size_t buflen) size_t buflen)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL)) if (!nfs_server_capable(inode, NFS_CAP_SECURITY_LABEL))
...@@ -6269,7 +6325,9 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock ...@@ -6269,7 +6325,9 @@ static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock
static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request) static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
do { do {
...@@ -6833,6 +6891,7 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock * ...@@ -6833,6 +6891,7 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *
struct nfs4_exception exception = { struct nfs4_exception exception = {
.state = state, .state = state,
.inode = state->inode, .inode = state->inode,
.interruptible = true,
}; };
int err; int err;
...@@ -7246,7 +7305,9 @@ int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir, ...@@ -7246,7 +7305,9 @@ int nfs4_proc_fs_locations(struct rpc_clnt *client, struct inode *dir,
struct nfs4_fs_locations *fs_locations, struct nfs4_fs_locations *fs_locations,
struct page *page) struct page *page)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
do { do {
err = _nfs4_proc_fs_locations(client, dir, name, err = _nfs4_proc_fs_locations(client, dir, name,
...@@ -7389,7 +7450,9 @@ int nfs4_proc_get_locations(struct inode *inode, ...@@ -7389,7 +7450,9 @@ int nfs4_proc_get_locations(struct inode *inode,
struct nfs_client *clp = server->nfs_client; struct nfs_client *clp = server->nfs_client;
const struct nfs4_mig_recovery_ops *ops = const struct nfs4_mig_recovery_ops *ops =
clp->cl_mvops->mig_recovery_ops; clp->cl_mvops->mig_recovery_ops;
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int status; int status;
dprintk("%s: FSID %llx:%llx on \"%s\"\n", __func__, dprintk("%s: FSID %llx:%llx on \"%s\"\n", __func__,
...@@ -7513,7 +7576,9 @@ int nfs4_proc_fsid_present(struct inode *inode, const struct cred *cred) ...@@ -7513,7 +7576,9 @@ int nfs4_proc_fsid_present(struct inode *inode, const struct cred *cred)
struct nfs_client *clp = server->nfs_client; struct nfs_client *clp = server->nfs_client;
const struct nfs4_mig_recovery_ops *ops = const struct nfs4_mig_recovery_ops *ops =
clp->cl_mvops->mig_recovery_ops; clp->cl_mvops->mig_recovery_ops;
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int status; int status;
dprintk("%s: FSID %llx:%llx on \"%s\"\n", __func__, dprintk("%s: FSID %llx:%llx on \"%s\"\n", __func__,
...@@ -7579,7 +7644,9 @@ static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct ...@@ -7579,7 +7644,9 @@ static int _nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, struct
int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name, int nfs4_proc_secinfo(struct inode *dir, const struct qstr *name,
struct nfs4_secinfo_flavors *flavors) struct nfs4_secinfo_flavors *flavors)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
do { do {
err = -NFS4ERR_WRONGSEC; err = -NFS4ERR_WRONGSEC;
...@@ -9269,7 +9336,9 @@ static int ...@@ -9269,7 +9336,9 @@ static int
nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle, nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors) struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
do { do {
/* first try using integrity protection */ /* first try using integrity protection */
...@@ -9436,7 +9505,9 @@ static int nfs41_test_stateid(struct nfs_server *server, ...@@ -9436,7 +9505,9 @@ static int nfs41_test_stateid(struct nfs_server *server,
nfs4_stateid *stateid, nfs4_stateid *stateid,
const struct cred *cred) const struct cred *cred)
{ {
struct nfs4_exception exception = { }; struct nfs4_exception exception = {
.interruptible = true,
};
int err; int err;
do { do {
err = _nfs41_test_stateid(server, stateid, cred); err = _nfs41_test_stateid(server, stateid, cred);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment