diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-12-02 13:54:59 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-12-05 18:30:53 -0500 |
commit | 1fa8064429d0acbf5bbf3c8a53f65679fdacc75e (patch) | |
tree | 86e9c0420815d6029c47d836bf3d7a4c93098c3c /fs/nfs/nfs4session.c | |
parent | c05eecf636101dd4347b2d8fa457626bf0088e0a (diff) |
NFSv4.1: Try to eliminate outliers when updating target_highest_slotid
Look for sudden changes in the first and second derivatives in order
to eliminate outlier changes to target_highest_slotid (which are
due to out-of-order RPC replies).
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/nfs4session.c')
-rw-r--r-- | fs/nfs/nfs4session.c | 63 |
1 files changed, 58 insertions, 5 deletions
diff --git a/fs/nfs/nfs4session.c b/fs/nfs/nfs4session.c index 066cfa101b41..ed5aa9fa9c7b 100644 --- a/fs/nfs/nfs4session.c +++ b/fs/nfs/nfs4session.c | |||
@@ -178,6 +178,8 @@ static void nfs4_reset_slot_table(struct nfs4_slot_table *tbl, | |||
178 | tbl->highest_used_slotid = NFS4_NO_SLOT; | 178 | tbl->highest_used_slotid = NFS4_NO_SLOT; |
179 | tbl->target_highest_slotid = server_highest_slotid; | 179 | tbl->target_highest_slotid = server_highest_slotid; |
180 | tbl->server_highest_slotid = server_highest_slotid; | 180 | tbl->server_highest_slotid = server_highest_slotid; |
181 | tbl->d_target_highest_slotid = 0; | ||
182 | tbl->d2_target_highest_slotid = 0; | ||
181 | tbl->max_slotid = server_highest_slotid; | 183 | tbl->max_slotid = server_highest_slotid; |
182 | } | 184 | } |
183 | 185 | ||
@@ -292,6 +294,8 @@ void nfs41_set_target_slotid(struct nfs4_slot_table *tbl, | |||
292 | { | 294 | { |
293 | spin_lock(&tbl->slot_tbl_lock); | 295 | spin_lock(&tbl->slot_tbl_lock); |
294 | nfs41_set_target_slotid_locked(tbl, target_highest_slotid); | 296 | nfs41_set_target_slotid_locked(tbl, target_highest_slotid); |
297 | tbl->d_target_highest_slotid = 0; | ||
298 | tbl->d2_target_highest_slotid = 0; | ||
295 | spin_unlock(&tbl->slot_tbl_lock); | 299 | spin_unlock(&tbl->slot_tbl_lock); |
296 | } | 300 | } |
297 | 301 | ||
@@ -307,16 +311,65 @@ static void nfs41_set_server_slotid_locked(struct nfs4_slot_table *tbl, | |||
307 | tbl->server_highest_slotid = highest_slotid; | 311 | tbl->server_highest_slotid = highest_slotid; |
308 | } | 312 | } |
309 | 313 | ||
314 | static s32 nfs41_derivative_target_slotid(s32 s1, s32 s2) | ||
315 | { | ||
316 | s1 -= s2; | ||
317 | if (s1 == 0) | ||
318 | return 0; | ||
319 | if (s1 < 0) | ||
320 | return (s1 - 1) >> 1; | ||
321 | return (s1 + 1) >> 1; | ||
322 | } | ||
323 | |||
324 | static int nfs41_sign_s32(s32 s1) | ||
325 | { | ||
326 | if (s1 > 0) | ||
327 | return 1; | ||
328 | if (s1 < 0) | ||
329 | return -1; | ||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static bool nfs41_same_sign_or_zero_s32(s32 s1, s32 s2) | ||
334 | { | ||
335 | if (!s1 || !s2) | ||
336 | return true; | ||
337 | return nfs41_sign_s32(s1) == nfs41_sign_s32(s2); | ||
338 | } | ||
339 | |||
340 | /* Try to eliminate outliers by checking for sharp changes in the | ||
341 | * derivatives and second derivatives | ||
342 | */ | ||
343 | static bool nfs41_is_outlier_target_slotid(struct nfs4_slot_table *tbl, | ||
344 | u32 new_target) | ||
345 | { | ||
346 | s32 d_target, d2_target; | ||
347 | bool ret = true; | ||
348 | |||
349 | d_target = nfs41_derivative_target_slotid(new_target, | ||
350 | tbl->target_highest_slotid); | ||
351 | d2_target = nfs41_derivative_target_slotid(d_target, | ||
352 | tbl->d_target_highest_slotid); | ||
353 | /* Is first derivative same sign? */ | ||
354 | if (nfs41_same_sign_or_zero_s32(d_target, tbl->d_target_highest_slotid)) | ||
355 | ret = false; | ||
356 | /* Is second derivative same sign? */ | ||
357 | if (nfs41_same_sign_or_zero_s32(d2_target, tbl->d2_target_highest_slotid)) | ||
358 | ret = false; | ||
359 | tbl->d_target_highest_slotid = d_target; | ||
360 | tbl->d2_target_highest_slotid = d2_target; | ||
361 | return ret; | ||
362 | } | ||
363 | |||
310 | void nfs41_update_target_slotid(struct nfs4_slot_table *tbl, | 364 | void nfs41_update_target_slotid(struct nfs4_slot_table *tbl, |
311 | struct nfs4_slot *slot, | 365 | struct nfs4_slot *slot, |
312 | struct nfs4_sequence_res *res) | 366 | struct nfs4_sequence_res *res) |
313 | { | 367 | { |
314 | spin_lock(&tbl->slot_tbl_lock); | 368 | spin_lock(&tbl->slot_tbl_lock); |
315 | if (tbl->generation != slot->generation) | 369 | if (!nfs41_is_outlier_target_slotid(tbl, res->sr_target_highest_slotid)) |
316 | goto out; | 370 | nfs41_set_target_slotid_locked(tbl, res->sr_target_highest_slotid); |
317 | nfs41_set_server_slotid_locked(tbl, res->sr_highest_slotid); | 371 | if (tbl->generation == slot->generation) |
318 | nfs41_set_target_slotid_locked(tbl, res->sr_target_highest_slotid); | 372 | nfs41_set_server_slotid_locked(tbl, res->sr_highest_slotid); |
319 | out: | ||
320 | spin_unlock(&tbl->slot_tbl_lock); | 373 | spin_unlock(&tbl->slot_tbl_lock); |
321 | } | 374 | } |
322 | 375 | ||