diff options
| author | J. Bruce Fields <bfields@citi.umich.edu> | 2008-03-18 19:00:19 -0400 |
|---|---|---|
| committer | J. Bruce Fields <bfields@citi.umich.edu> | 2008-09-29 18:13:10 -0400 |
| commit | c8ab5f2a13fb41a878863c61a1e27d78f1844b5e (patch) | |
| tree | 869ce6a2a51581d09011aeb5e804b0d1ab39a7b9 | |
| parent | 8fafa90082ab18859d97627fc454edf12f7efbff (diff) | |
lockd: don't depend on lockd main loop to end grace
End lockd's grace period using schedule_delayed_work() instead of a
check on every pass through the main loop.
After a later patch, we'll depend on lockd to end its grace period even
if it's not currently handling requests; so it shouldn't depend on being
woken up from the main loop to do so.
Also, Nakano Hiroaki (who independently produced a similar patch)
noticed that the current behavior is buggy in the face of jiffies
wraparound:
"lockd uses time_before() to determine whether the grace period
has expired. This would seem to be enough to avoid timer
wrap-around issues, but, unfortunately, that is not the case.
The time_* family of comparison functions can be safely used to
compare jiffies relatively close in time, but they stop working
after approximately LONG_MAX/2 ticks. nfsd can suffer this
problem because the time_before() comparison in lockd() is not
performed until the first request comes in, which means that if
there is no lockd traffic for more than LONG_MAX/2 ticks we are
screwed.
"The implication of this is that once time_before() starts
misbehaving any attempt from a NFS client to execute fcntl()
will be received with a NLM_LCK_DENIED_GRACE_PERIOD message for
25 days (assuming HZ=1000). In other words, the 50 seconds grace
period could turn into a grace period of 50 days or more.
"Note: This bug was analyzed independently by Oda-san
<oda@valinux.co.jp> and myself."
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Cc: Nakano Hiroaki <nakano.hiroaki@oss.ntt.co.jp>
Cc: Itsuro Oda <oda@valinux.co.jp>
| -rw-r--r-- | fs/lockd/svc.c | 24 |
1 files changed, 13 insertions, 11 deletions
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index bdc607bb25e9..f345ef7fb8ae 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c | |||
| @@ -97,15 +97,20 @@ unsigned long get_nfs_grace_period(void) | |||
| 97 | } | 97 | } |
| 98 | EXPORT_SYMBOL(get_nfs_grace_period); | 98 | EXPORT_SYMBOL(get_nfs_grace_period); |
| 99 | 99 | ||
| 100 | static unsigned long set_grace_period(void) | 100 | static void grace_ender(struct work_struct *not_used) |
| 101 | { | 101 | { |
| 102 | nlmsvc_grace_period = 1; | 102 | nlmsvc_grace_period = 0; |
| 103 | return get_nfs_grace_period() + jiffies; | ||
| 104 | } | 103 | } |
| 105 | 104 | ||
| 106 | static inline void clear_grace_period(void) | 105 | static DECLARE_DELAYED_WORK(grace_period_end, grace_ender); |
| 106 | |||
| 107 | static void set_grace_period(void) | ||
| 107 | { | 108 | { |
| 108 | nlmsvc_grace_period = 0; | 109 | unsigned long grace_period = get_nfs_grace_period() + jiffies; |
| 110 | |||
| 111 | nlmsvc_grace_period = 1; | ||
| 112 | cancel_delayed_work_sync(&grace_period_end); | ||
| 113 | schedule_delayed_work(&grace_period_end, grace_period); | ||
| 109 | } | 114 | } |
| 110 | 115 | ||
| 111 | /* | 116 | /* |
| @@ -116,7 +121,6 @@ lockd(void *vrqstp) | |||
| 116 | { | 121 | { |
| 117 | int err = 0, preverr = 0; | 122 | int err = 0, preverr = 0; |
| 118 | struct svc_rqst *rqstp = vrqstp; | 123 | struct svc_rqst *rqstp = vrqstp; |
| 119 | unsigned long grace_period_expire; | ||
| 120 | 124 | ||
| 121 | /* try_to_freeze() is called from svc_recv() */ | 125 | /* try_to_freeze() is called from svc_recv() */ |
| 122 | set_freezable(); | 126 | set_freezable(); |
| @@ -139,7 +143,7 @@ lockd(void *vrqstp) | |||
| 139 | nlm_timeout = LOCKD_DFLT_TIMEO; | 143 | nlm_timeout = LOCKD_DFLT_TIMEO; |
| 140 | nlmsvc_timeout = nlm_timeout * HZ; | 144 | nlmsvc_timeout = nlm_timeout * HZ; |
| 141 | 145 | ||
| 142 | grace_period_expire = set_grace_period(); | 146 | set_grace_period(); |
| 143 | 147 | ||
| 144 | /* | 148 | /* |
| 145 | * The main request loop. We don't terminate until the last | 149 | * The main request loop. We don't terminate until the last |
| @@ -153,16 +157,13 @@ lockd(void *vrqstp) | |||
| 153 | flush_signals(current); | 157 | flush_signals(current); |
| 154 | if (nlmsvc_ops) { | 158 | if (nlmsvc_ops) { |
| 155 | nlmsvc_invalidate_all(); | 159 | nlmsvc_invalidate_all(); |
| 156 | grace_period_expire = set_grace_period(); | 160 | set_grace_period(); |
| 157 | } | 161 | } |
| 158 | continue; | 162 | continue; |
| 159 | } | 163 | } |
| 160 | 164 | ||
| 161 | timeout = nlmsvc_retry_blocked(); | 165 | timeout = nlmsvc_retry_blocked(); |
| 162 | 166 | ||
| 163 | if (time_before(grace_period_expire, jiffies)) | ||
| 164 | clear_grace_period(); | ||
| 165 | |||
| 166 | /* | 167 | /* |
| 167 | * Find a socket with data available and call its | 168 | * Find a socket with data available and call its |
| 168 | * recvfrom routine. | 169 | * recvfrom routine. |
| @@ -189,6 +190,7 @@ lockd(void *vrqstp) | |||
| 189 | svc_process(rqstp); | 190 | svc_process(rqstp); |
| 190 | } | 191 | } |
| 191 | flush_signals(current); | 192 | flush_signals(current); |
| 193 | cancel_delayed_work_sync(&grace_period_end); | ||
| 192 | if (nlmsvc_ops) | 194 | if (nlmsvc_ops) |
| 193 | nlmsvc_invalidate_all(); | 195 | nlmsvc_invalidate_all(); |
| 194 | nlm_shutdown_hosts(); | 196 | nlm_shutdown_hosts(); |
