Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* |
| 2 | * fs/nfs/nfs4renewd.c |
| 3 | * |
| 4 | * Copyright (c) 2002 The Regents of the University of Michigan. |
| 5 | * All rights reserved. |
| 6 | * |
| 7 | * Kendrick Smith <kmsmith@umich.edu> |
| 8 | * |
| 9 | * Redistribution and use in source and binary forms, with or without |
| 10 | * modification, are permitted provided that the following conditions |
| 11 | * are met: |
| 12 | * |
| 13 | * 1. Redistributions of source code must retain the above copyright |
| 14 | * notice, this list of conditions and the following disclaimer. |
| 15 | * 2. Redistributions in binary form must reproduce the above copyright |
| 16 | * notice, this list of conditions and the following disclaimer in the |
| 17 | * documentation and/or other materials provided with the distribution. |
| 18 | * 3. Neither the name of the University nor the names of its |
| 19 | * contributors may be used to endorse or promote products derived |
| 20 | * from this software without specific prior written permission. |
| 21 | * |
| 22 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| 23 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| 24 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 25 | * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
| 26 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| 27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| 28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| 29 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| 30 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| 31 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| 32 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 33 | * |
| 34 | * Implementation of the NFSv4 "renew daemon", which wakes up periodically to |
| 35 | * send a RENEW, to keep state alive on the server. The daemon is implemented |
| 36 | * as an rpc_task, not a real kernel thread, so it always runs in rpciod's |
| 37 | * context. There is one renewd per nfs_server. |
| 38 | * |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 39 | */ |
| 40 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 41 | #include <linux/mm.h> |
| 42 | #include <linux/pagemap.h> |
| 43 | #include <linux/sunrpc/sched.h> |
| 44 | #include <linux/sunrpc/clnt.h> |
| 45 | |
| 46 | #include <linux/nfs.h> |
| 47 | #include <linux/nfs4.h> |
| 48 | #include <linux/nfs_fs.h> |
Trond Myklebust | 4ce7971 | 2005-06-22 17:16:21 +0000 | [diff] [blame] | 49 | #include "nfs4_fs.h" |
Trond Myklebust | 58d9714 | 2006-01-03 09:55:24 +0100 | [diff] [blame] | 50 | #include "delegation.h" |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 51 | |
Chuck Lever | e3c0fb7 | 2012-05-21 22:45:24 -0400 | [diff] [blame] | 52 | #define NFSDBG_FACILITY NFSDBG_STATE |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 53 | |
| 54 | void |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 55 | nfs4_renew_state(struct work_struct *work) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 56 | { |
Trond Myklebust | c48f4f3 | 2010-06-16 09:52:27 -0400 | [diff] [blame] | 57 | const struct nfs4_state_maintenance_ops *ops; |
David Howells | 65f27f3 | 2006-11-22 14:55:48 +0000 | [diff] [blame] | 58 | struct nfs_client *clp = |
| 59 | container_of(work, struct nfs_client, cl_renewd.work); |
NeilBrown | a52458b | 2018-12-03 11:30:31 +1100 | [diff] [blame] | 60 | const struct cred *cred; |
Alexandros Batsakis | dc96aef | 2010-02-05 03:45:04 -0800 | [diff] [blame] | 61 | long lease; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 62 | unsigned long last, now; |
Trond Myklebust | 2f60ea6 | 2011-08-24 15:07:37 -0400 | [diff] [blame] | 63 | unsigned renew_flags = 0; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 64 | |
Trond Myklebust | c48f4f3 | 2010-06-16 09:52:27 -0400 | [diff] [blame] | 65 | ops = clp->cl_mvops->state_renewal_ops; |
Harvey Harrison | 3110ff8 | 2008-05-02 13:42:44 -0700 | [diff] [blame] | 66 | dprintk("%s: start\n", __func__); |
Chuck Lever | fca5238e | 2010-12-24 01:32:32 +0000 | [diff] [blame] | 67 | |
Andy Adamson | d3b4c9d | 2011-03-01 01:34:10 +0000 | [diff] [blame] | 68 | if (test_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state)) |
Trond Myklebust | 58d9714 | 2006-01-03 09:55:24 +0100 | [diff] [blame] | 69 | goto out; |
Chuck Lever | fca5238e | 2010-12-24 01:32:32 +0000 | [diff] [blame] | 70 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 71 | lease = clp->cl_lease_time; |
| 72 | last = clp->cl_last_renewal; |
| 73 | now = jiffies; |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 74 | /* Are we close to a lease timeout? */ |
Trond Myklebust | 2f60ea6 | 2011-08-24 15:07:37 -0400 | [diff] [blame] | 75 | if (time_after(now, last + lease/3)) |
| 76 | renew_flags |= NFS4_RENEW_TIMEOUT; |
| 77 | if (nfs_delegations_present(clp)) |
| 78 | renew_flags |= NFS4_RENEW_DELEGATION_CB; |
| 79 | |
| 80 | if (renew_flags != 0) { |
NeilBrown | f15e1e8 | 2018-12-03 11:30:30 +1100 | [diff] [blame] | 81 | cred = ops->get_state_renewal_cred(clp); |
Trond Myklebust | b0d3ded | 2008-12-23 15:21:50 -0500 | [diff] [blame] | 82 | if (cred == NULL) { |
Trond Myklebust | 2f60ea6 | 2011-08-24 15:07:37 -0400 | [diff] [blame] | 83 | if (!(renew_flags & NFS4_RENEW_DELEGATION_CB)) { |
Trond Myklebust | b0d3ded | 2008-12-23 15:21:50 -0500 | [diff] [blame] | 84 | set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state); |
| 85 | goto out; |
| 86 | } |
| 87 | nfs_expire_all_delegations(clp); |
| 88 | } else { |
Andy Adamson | d1f456b | 2014-09-29 12:31:57 -0400 | [diff] [blame] | 89 | int ret; |
| 90 | |
Trond Myklebust | b0d3ded | 2008-12-23 15:21:50 -0500 | [diff] [blame] | 91 | /* Queue an asynchronous RENEW. */ |
Andy Adamson | d1f456b | 2014-09-29 12:31:57 -0400 | [diff] [blame] | 92 | ret = ops->sched_state_renewal(clp, cred, renew_flags); |
NeilBrown | a52458b | 2018-12-03 11:30:31 +1100 | [diff] [blame] | 93 | put_cred(cred); |
Andy Adamson | d1f456b | 2014-09-29 12:31:57 -0400 | [diff] [blame] | 94 | switch (ret) { |
| 95 | default: |
| 96 | goto out_exp; |
| 97 | case -EAGAIN: |
| 98 | case -ENOMEM: |
| 99 | break; |
| 100 | } |
Trond Myklebust | b0d3ded | 2008-12-23 15:21:50 -0500 | [diff] [blame] | 101 | } |
Alexandros Batsakis | dc96aef | 2010-02-05 03:45:04 -0800 | [diff] [blame] | 102 | } else { |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 103 | dprintk("%s: failed to call renewd. Reason: lease not expired \n", |
Harvey Harrison | 3110ff8 | 2008-05-02 13:42:44 -0700 | [diff] [blame] | 104 | __func__); |
Alexandros Batsakis | dc96aef | 2010-02-05 03:45:04 -0800 | [diff] [blame] | 105 | } |
| 106 | nfs4_schedule_state_renewal(clp); |
| 107 | out_exp: |
Trond Myklebust | b7391f4 | 2008-12-23 15:21:52 -0500 | [diff] [blame] | 108 | nfs_expire_unreferenced_delegations(clp); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 109 | out: |
Harvey Harrison | 3110ff8 | 2008-05-02 13:42:44 -0700 | [diff] [blame] | 110 | dprintk("%s: done\n", __func__); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 111 | } |
| 112 | |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 113 | void |
David Howells | adfa6f9 | 2006-08-22 20:06:08 -0400 | [diff] [blame] | 114 | nfs4_schedule_state_renewal(struct nfs_client *clp) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 115 | { |
| 116 | long timeout; |
| 117 | |
| 118 | spin_lock(&clp->cl_lock); |
| 119 | timeout = (2 * clp->cl_lease_time) / 3 + (long)clp->cl_last_renewal |
| 120 | - (long)jiffies; |
| 121 | if (timeout < 5 * HZ) |
| 122 | timeout = 5 * HZ; |
| 123 | dprintk("%s: requeueing work. Lease period = %ld\n", |
Harvey Harrison | 3110ff8 | 2008-05-02 13:42:44 -0700 | [diff] [blame] | 124 | __func__, (timeout + HZ - 1) / HZ); |
Tejun Heo | 41f63c5 | 2012-08-03 10:30:47 -0700 | [diff] [blame] | 125 | mod_delayed_work(system_wq, &clp->cl_renewd, timeout); |
Trond Myklebust | 5dd3177 | 2006-08-24 01:03:05 -0400 | [diff] [blame] | 126 | set_bit(NFS_CS_RENEWD, &clp->cl_res_state); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 127 | spin_unlock(&clp->cl_lock); |
| 128 | } |
| 129 | |
| 130 | void |
David Howells | adfa6f9 | 2006-08-22 20:06:08 -0400 | [diff] [blame] | 131 | nfs4_kill_renewd(struct nfs_client *clp) |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 132 | { |
Trond Myklebust | 3d39c69 | 2007-08-07 15:28:33 -0400 | [diff] [blame] | 133 | cancel_delayed_work_sync(&clp->cl_renewd); |
Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 134 | } |
| 135 | |
Trond Myklebust | fb10fb6 | 2016-08-05 19:13:08 -0400 | [diff] [blame] | 136 | /** |
| 137 | * nfs4_set_lease_period - Sets the lease period on a nfs_client |
| 138 | * |
| 139 | * @clp: pointer to nfs_client |
| 140 | * @lease: new value for lease period |
Trond Myklebust | fb10fb6 | 2016-08-05 19:13:08 -0400 | [diff] [blame] | 141 | */ |
| 142 | void nfs4_set_lease_period(struct nfs_client *clp, |
Robert Milkowski | 7dc2993 | 2020-01-30 09:43:25 +0000 | [diff] [blame] | 143 | unsigned long lease) |
Trond Myklebust | fb10fb6 | 2016-08-05 19:13:08 -0400 | [diff] [blame] | 144 | { |
| 145 | spin_lock(&clp->cl_lock); |
| 146 | clp->cl_lease_time = lease; |
Trond Myklebust | fb10fb6 | 2016-08-05 19:13:08 -0400 | [diff] [blame] | 147 | spin_unlock(&clp->cl_lock); |
Trond Myklebust | 8d48032 | 2016-08-05 19:03:31 -0400 | [diff] [blame] | 148 | |
| 149 | /* Cap maximum reconnect timeout at 1/2 lease period */ |
Trond Myklebust | 26ae102 | 2017-02-08 11:17:55 -0500 | [diff] [blame] | 150 | rpc_set_connect_timeout(clp->cl_rpcclient, lease, lease >> 1); |
Trond Myklebust | fb10fb6 | 2016-08-05 19:13:08 -0400 | [diff] [blame] | 151 | } |