NFS: Add mount option 'softreval'
authorTrond Myklebust <trondmy@gmail.com>
Mon, 6 Jan 2020 20:39:37 +0000 (15:39 -0500)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Wed, 15 Jan 2020 15:54:33 +0000 (10:54 -0500)
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: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
fs/nfs/fs_context.c
fs/nfs/inode.c
fs/nfs/nfs3proc.c
fs/nfs/nfs4proc.c
fs/nfs/proc.c
fs/nfs/super.c
include/linux/nfs_fs_sb.h

index 429315c011aeb490b303c9f47c843d1d27f88240..0247dcb7b316217ec06b56d1fb93c9c5125dc72a 100644 (file)
@@ -73,6 +73,7 @@ enum nfs_param {
        Opt_sloppy,
        Opt_soft,
        Opt_softerr,
+       Opt_softreval,
        Opt_source,
        Opt_tcp,
        Opt_timeo,
@@ -128,6 +129,7 @@ static const struct fs_parameter_spec nfs_param_specs[] = {
        fsparam_flag  ("sloppy",        Opt_sloppy),
        fsparam_flag  ("soft",          Opt_soft),
        fsparam_flag  ("softerr",       Opt_softerr),
+       fsparam_flag  ("softreval",     Opt_softreval),
        fsparam_string("source",        Opt_source),
        fsparam_flag  ("tcp",           Opt_tcp),
        fsparam_u32   ("timeo",         Opt_timeo),
@@ -460,11 +462,19 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
                ctx->flags &= ~NFS_MOUNT_SOFTERR;
                break;
        case Opt_softerr:
-               ctx->flags |= NFS_MOUNT_SOFTERR;
+               ctx->flags |= NFS_MOUNT_SOFTERR | NFS_MOUNT_SOFTREVAL;
                ctx->flags &= ~NFS_MOUNT_SOFT;
                break;
        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;
        case Opt_posix:
                if (result.negated)
index b0b4b9f303fd85a090dfaab4d3b904ac222c6243..71dfc9d2fc3d3194efec2000a5d2ef9d66bddb6a 100644 (file)
@@ -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",
                         inode->i_sb->s_id,
                         (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);
                        if (!S_ISDIR(inode->i_mode))
                                set_bit(NFS_INO_STALE, &NFS_I(inode)->flags);
index 67a05f35bb89a71e87f4cf513468637dbc663707..19f3d1b2807ee82b2c030f4837a55613767b077a 100644 (file)
@@ -110,10 +110,15 @@ nfs3_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
                .rpc_resp       = fattr,
        };
        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");
        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);
        return status;
 }
index 904335b91b6a3f450ee91c38d09837ecbfdd7d4b..294d27be38683cc78c4114631d231b2194b54f04 100644 (file)
@@ -1097,11 +1097,12 @@ static int nfs4_call_sync_custom(struct rpc_task_setup *task_setup)
        return ret;
 }
 
-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)
+static int nfs4_do_call_sync(struct rpc_clnt *clnt,
+                            struct nfs_server *server,
+                            struct rpc_message *msg,
+                            struct nfs4_sequence_args *args,
+                            struct nfs4_sequence_res *res,
+                            unsigned short task_flags)
 {
        struct nfs_client *clp = server->nfs_client;
        struct nfs4_call_sync_data data = {
@@ -1113,12 +1114,23 @@ static int nfs4_call_sync_sequence(struct rpc_clnt *clnt,
                .rpc_client = clnt,
                .rpc_message = msg,
                .callback_ops = clp->cl_mvops->call_sync_ops,
-               .callback_data = &data
+               .callback_data = &data,
+               .flags = task_flags,
        };
 
        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,
                   struct nfs_server *server,
                   struct rpc_message *msg,
@@ -4064,11 +4076,18 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
                .rpc_argp = &args,
                .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);
 
        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,
index 44a15523bf408cfff167f0dd4bb60153a1b9bab0..0451a094e89ee1364af21b8ad3de0d29b869338a 100644 (file)
@@ -108,10 +108,15 @@ nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
                .rpc_resp       = fattr,
        };
        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");
        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);
        return status;
 }
index 76e0198adcfa655de974d3c269b867a488d7282b..dada09b391c653a7f0fa1e6c8dd87daba0b204be 100644 (file)
@@ -375,6 +375,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
        } nfs_info[] = {
                { NFS_MOUNT_SOFT, ",soft", "" },
                { NFS_MOUNT_SOFTERR, ",softerr", "" },
+               { NFS_MOUNT_SOFTREVAL, ",softreval", "" },
                { NFS_MOUNT_POSIX, ",posix", "" },
                { NFS_MOUNT_NOCTO, ",nocto", "" },
                { NFS_MOUNT_NOAC, ",noac", "" },
index c176f705bf98f025d0e68596f30abdf75c41b790..465fa98258a315c71d25f677405fa15b42c6ef85 100644 (file)
@@ -152,6 +152,7 @@ struct nfs_server {
 #define NFS_MOUNT_LOCAL_FLOCK          0x100000
 #define NFS_MOUNT_LOCAL_FCNTL          0x200000
 #define NFS_MOUNT_SOFTERR              0x400000
+#define NFS_MOUNT_SOFTREVAL            0x800000
 
        unsigned int            caps;           /* server capabilities */
        unsigned int            rsize;          /* read size */