Commit c74dfe97 authored by Trond Myklebust's avatar Trond Myklebust Committed by Anna Schumaker

NFS: Add mount option 'softreval'

Add a mount option 'softreval' that allows attribute revalidation 'getattr'
calls to time out, and causes them to fall back to using the cached
attributes.
The use case for this option is for ensuring that we can still (slowly)
traverse paths and use cached information even when the server is down.
Once the server comes back up again, the getattr calls start succeeding,
and the caches will revalidate as usual.

The 'softreval' mount option is automatically enabled if you have
specified 'softerr'.  It can be turned off using the options
'nosoftreval', or 'hard'.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarAnna Schumaker <Anna.Schumaker@Netapp.com>
parent 5c965db8
...@@ -73,6 +73,7 @@ enum nfs_param { ...@@ -73,6 +73,7 @@ enum nfs_param {
Opt_sloppy, Opt_sloppy,
Opt_soft, Opt_soft,
Opt_softerr, Opt_softerr,
Opt_softreval,
Opt_source, Opt_source,
Opt_tcp, Opt_tcp,
Opt_timeo, Opt_timeo,
...@@ -128,6 +129,7 @@ static const struct fs_parameter_spec nfs_param_specs[] = { ...@@ -128,6 +129,7 @@ static const struct fs_parameter_spec nfs_param_specs[] = {
fsparam_flag ("sloppy", Opt_sloppy), fsparam_flag ("sloppy", Opt_sloppy),
fsparam_flag ("soft", Opt_soft), fsparam_flag ("soft", Opt_soft),
fsparam_flag ("softerr", Opt_softerr), fsparam_flag ("softerr", Opt_softerr),
fsparam_flag ("softreval", Opt_softreval),
fsparam_string("source", Opt_source), fsparam_string("source", Opt_source),
fsparam_flag ("tcp", Opt_tcp), fsparam_flag ("tcp", Opt_tcp),
fsparam_u32 ("timeo", Opt_timeo), fsparam_u32 ("timeo", Opt_timeo),
...@@ -460,11 +462,19 @@ static int nfs_fs_context_parse_param(struct fs_context *fc, ...@@ -460,11 +462,19 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
ctx->flags &= ~NFS_MOUNT_SOFTERR; ctx->flags &= ~NFS_MOUNT_SOFTERR;
break; break;
case Opt_softerr: case Opt_softerr:
ctx->flags |= NFS_MOUNT_SOFTERR; ctx->flags |= NFS_MOUNT_SOFTERR | NFS_MOUNT_SOFTREVAL;
ctx->flags &= ~NFS_MOUNT_SOFT; ctx->flags &= ~NFS_MOUNT_SOFT;
break; break;
case Opt_hard: case Opt_hard:
ctx->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR); ctx->flags &= ~(NFS_MOUNT_SOFT |
NFS_MOUNT_SOFTERR |
NFS_MOUNT_SOFTREVAL);
break;
case Opt_softreval:
if (result.negated)
ctx->flags &= ~NFS_MOUNT_SOFTREVAL;
else
ctx->flags &= NFS_MOUNT_SOFTREVAL;
break; break;
case Opt_posix: case Opt_posix:
if (result.negated) if (result.negated)
......
...@@ -1156,7 +1156,13 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) ...@@ -1156,7 +1156,13 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) getattr failed, error=%d\n", dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) getattr failed, error=%d\n",
inode->i_sb->s_id, inode->i_sb->s_id,
(unsigned long long)NFS_FILEID(inode), status); (unsigned long long)NFS_FILEID(inode), status);
if (status == -ESTALE) { switch (status) {
case -ETIMEDOUT:
/* A soft timeout occurred. Use cached information? */
if (server->flags & NFS_MOUNT_SOFTREVAL)
status = 0;
break;
case -ESTALE:
nfs_zap_caches(inode); nfs_zap_caches(inode);
if (!S_ISDIR(inode->i_mode)) if (!S_ISDIR(inode->i_mode))
set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
......
...@@ -110,10 +110,15 @@ nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -110,10 +110,15 @@ nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
.rpc_resp = fattr, .rpc_resp = fattr,
}; };
int status; int status;
unsigned short task_flags = 0;
/* Is this is an attribute revalidation, subject to softreval? */
if (inode && (server->flags & NFS_MOUNT_SOFTREVAL))
task_flags |= RPC_TASK_TIMEOUT;
dprintk("NFS call getattr\n"); dprintk("NFS call getattr\n");
nfs_fattr_init(fattr); nfs_fattr_init(fattr);
status = rpc_call_sync(server->client, &msg, 0); status = rpc_call_sync(server->client, &msg, task_flags);
dprintk("NFS reply getattr: %d\n", status); dprintk("NFS reply getattr: %d\n", status);
return status; return status;
} }
......
...@@ -1097,11 +1097,12 @@ static int nfs4_call_sync_custom(struct rpc_task_setup *task_setup) ...@@ -1097,11 +1097,12 @@ static int nfs4_call_sync_custom(struct rpc_task_setup *task_setup)
return ret; return ret;
} }
static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, static int nfs4_do_call_sync(struct rpc_clnt *clnt,
struct nfs_server *server, struct nfs_server *server,
struct rpc_message *msg, struct rpc_message *msg,
struct nfs4_sequence_args *args, struct nfs4_sequence_args *args,
struct nfs4_sequence_res *res) struct nfs4_sequence_res *res,
unsigned short task_flags)
{ {
struct nfs_client *clp = server->nfs_client; struct nfs_client *clp = server->nfs_client;
struct nfs4_call_sync_data data = { struct nfs4_call_sync_data data = {
...@@ -1113,12 +1114,23 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt, ...@@ -1113,12 +1114,23 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
.rpc_client = clnt, .rpc_client = clnt,
.rpc_message = msg, .rpc_message = msg,
.callback_ops = clp->cl_mvops->call_sync_ops, .callback_ops = clp->cl_mvops->call_sync_ops,
.callback_data = &data .callback_data = &data,
.flags = task_flags,
}; };
return nfs4_call_sync_custom(&task_setup); return nfs4_call_sync_custom(&task_setup);
} }
static 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)
{
return nfs4_do_call_sync(clnt, server, msg, args, res, 0);
}
int nfs4_call_sync(struct rpc_clnt *clnt, int nfs4_call_sync(struct rpc_clnt *clnt,
struct nfs_server *server, struct nfs_server *server,
struct rpc_message *msg, struct rpc_message *msg,
...@@ -4064,11 +4076,18 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -4064,11 +4076,18 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
.rpc_argp = &args, .rpc_argp = &args,
.rpc_resp = &res, .rpc_resp = &res,
}; };
unsigned short task_flags = 0;
/* Is this is an attribute revalidation, subject to softreval? */
if (inode && (server->flags & NFS_MOUNT_SOFTREVAL))
task_flags |= RPC_TASK_TIMEOUT;
nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, label), inode); nfs4_bitmap_copy_adjust(bitmask, nfs4_bitmask(server, label), inode);
nfs_fattr_init(fattr); nfs_fattr_init(fattr);
return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 0);
return nfs4_do_call_sync(server->client, server, &msg,
&args.seq_args, &res.seq_res, task_flags);
} }
int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
......
...@@ -108,10 +108,15 @@ nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, ...@@ -108,10 +108,15 @@ nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
.rpc_resp = fattr, .rpc_resp = fattr,
}; };
int status; int status;
unsigned short task_flags = 0;
/* Is this is an attribute revalidation, subject to softreval? */
if (inode && (server->flags & NFS_MOUNT_SOFTREVAL))
task_flags |= RPC_TASK_TIMEOUT;
dprintk("NFS call getattr\n"); dprintk("NFS call getattr\n");
nfs_fattr_init(fattr); nfs_fattr_init(fattr);
status = rpc_call_sync(server->client, &msg, 0); status = rpc_call_sync(server->client, &msg, task_flags);
dprintk("NFS reply getattr: %d\n", status); dprintk("NFS reply getattr: %d\n", status);
return status; return status;
} }
......
...@@ -375,6 +375,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, ...@@ -375,6 +375,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
} nfs_info[] = { } nfs_info[] = {
{ NFS_MOUNT_SOFT, ",soft", "" }, { NFS_MOUNT_SOFT, ",soft", "" },
{ NFS_MOUNT_SOFTERR, ",softerr", "" }, { NFS_MOUNT_SOFTERR, ",softerr", "" },
{ NFS_MOUNT_SOFTREVAL, ",softreval", "" },
{ NFS_MOUNT_POSIX, ",posix", "" }, { NFS_MOUNT_POSIX, ",posix", "" },
{ NFS_MOUNT_NOCTO, ",nocto", "" }, { NFS_MOUNT_NOCTO, ",nocto", "" },
{ NFS_MOUNT_NOAC, ",noac", "" }, { NFS_MOUNT_NOAC, ",noac", "" },
......
...@@ -152,6 +152,7 @@ struct nfs_server { ...@@ -152,6 +152,7 @@ struct nfs_server {
#define NFS_MOUNT_LOCAL_FLOCK 0x100000 #define NFS_MOUNT_LOCAL_FLOCK 0x100000
#define NFS_MOUNT_LOCAL_FCNTL 0x200000 #define NFS_MOUNT_LOCAL_FCNTL 0x200000
#define NFS_MOUNT_SOFTERR 0x400000 #define NFS_MOUNT_SOFTERR 0x400000
#define NFS_MOUNT_SOFTREVAL 0x800000
unsigned int caps; /* server capabilities */ unsigned int caps; /* server capabilities */
unsigned int rsize; /* read size */ unsigned int rsize; /* read size */
......
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