aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--fs/nfs/nfs4session.c63
-rw-r--r--fs/nfs/nfs4session.h2
2 files changed, 60 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
diff --git a/fs/nfs/nfs4session.h b/fs/nfs/nfs4session.h
index 7db739370164..04f834cab16c 100644
--- a/fs/nfs/nfs4session.h
+++ b/fs/nfs/nfs4session.h
@@ -38,6 +38,8 @@ struct nfs4_slot_table {
38 * op for dynamic resizing */ 38 * op for dynamic resizing */
39 u32 target_highest_slotid; /* Server max_slot target */ 39 u32 target_highest_slotid; /* Server max_slot target */
40 u32 server_highest_slotid; /* Server highest slotid */ 40 u32 server_highest_slotid; /* Server highest slotid */
41 s32 d_target_highest_slotid; /* Derivative */
42 s32 d2_target_highest_slotid; /* 2nd derivative */
41 unsigned long generation; /* Generation counter for 43 unsigned long generation; /* Generation counter for
42 target_highest_slotid */ 44 target_highest_slotid */
43 struct completion complete; 45 struct completion complete;