aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs4session.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2012-12-02 13:54:59 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-12-05 18:30:53 -0500
commit1fa8064429d0acbf5bbf3c8a53f65679fdacc75e (patch)
tree86e9c0420815d6029c47d836bf3d7a4c93098c3c /fs/nfs/nfs4session.c
parentc05eecf636101dd4347b2d8fa457626bf0088e0a (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.c63
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
314static 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
324static 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
333static 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 */
343static 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
310void nfs41_update_target_slotid(struct nfs4_slot_table *tbl, 364void 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);
319out:
320 spin_unlock(&tbl->slot_tbl_lock); 373 spin_unlock(&tbl->slot_tbl_lock);
321} 374}
322 375