Print this page
4827 nfs4: slow file locking
4837 NFSv4 client lock retry delay upper limit should be shorter
@@ -33,10 +33,14 @@
/*
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
*/
+/*
+ * Copyright (c) 2014, STRATO AG. All rights reserved.
+ */
+
#include <sys/param.h>
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/cred.h>
#include <sys/time.h>
@@ -288,12 +292,10 @@
* wait on pending writes.
*/
#define NFS4_WRITE_NOWAIT 0
#define NFS4_WRITE_WAIT 1
-#define NFS4_BASE_WAIT_TIME 1 /* 1 second */
-
/*
* Error flags used to pass information about certain special errors
* which need to be handled specially.
*/
#define NFS_EOF -98
@@ -360,10 +362,16 @@
void *lockt_denied_debug;
#endif
/*
+ * In milliseconds. Should be less than half of the lease time or better,
+ * less than one second.
+ */
+int nfs4_base_wait_time = 20;
+
+/*
* How long to wait before trying again if OPEN_CONFIRM gets ETIMEDOUT
* or NFS4ERR_RESOURCE.
*/
static int confirm_retry_sec = 30;
@@ -12971,14 +12979,14 @@
flock64_t *flk, short *whencep, vnode_t *vp, cred_t *search_cr,
cred_t **cred_otw)
{
/*
* set tick_delay to the base delay time.
- * (NFS4_BASE_WAIT_TIME is in secs)
+ * (nfs4_base_wait_time is in msecs)
*/
- *tick_delayp = drv_usectohz(NFS4_BASE_WAIT_TIME * 1000 * 1000);
+ *tick_delayp = drv_usectohz(nfs4_base_wait_time * 1000);
/*
* If lock is relative to EOF, we need the newest length of the
* file. Therefore invalidate the ATTR_CACHE.
*/
@@ -14745,42 +14753,56 @@
}
/*
* Wait for 'tick_delay' clock ticks.
* Implement exponential backoff until hit the lease_time of this nfs4_server.
- * NOTE: lock_lease_time is in seconds.
+ *
+ * The client should retry to acquire the lock faster than the lease period.
+ * We use roughly half of the lease time to use a similar calculation as it is
+ * used in nfs4_renew_lease_thread().
*
* XXX For future improvements, should implement a waiting queue scheme.
*/
static int
nfs4_block_and_wait(clock_t *tick_delay, rnode4_t *rp)
{
- long milliseconds_delay;
- time_t lock_lease_time;
+ long max_msec_delay = 1 * 1000; /* 1 sec */
+ nfs4_server_t *sp;
+ mntinfo4_t *mi = VTOMI4(RTOV4(rp));
/* wait tick_delay clock ticks or siginteruptus */
if (delay_sig(*tick_delay)) {
return (EINTR);
}
+
NFS4_DEBUG(nfs4_client_lock_debug, (CE_NOTE, "nfs4_block_and_wait: "
"reissue the lock request: blocked for %ld clock ticks: %ld "
"milliseconds", *tick_delay, drv_hztousec(*tick_delay) / 1000));
- /* get the lease time */
- lock_lease_time = r2lease_time(rp);
-
- /* drv_hztousec converts ticks to microseconds */
- milliseconds_delay = drv_hztousec(*tick_delay) / 1000;
- if (milliseconds_delay < lock_lease_time * 1000) {
- *tick_delay = 2 * *tick_delay;
- if (drv_hztousec(*tick_delay) > lock_lease_time * 1000 * 1000)
- *tick_delay = drv_usectohz(lock_lease_time*1000*1000);
+ /*
+ * Get the current lease time and propagation time for the server
+ * associated with the given file. Note that both times could
+ * change immediately after this section.
+ */
+ nfs_rw_enter_sig(&mi->mi_recovlock, RW_READER, 0);
+ sp = find_nfs4_server(mi);
+ if (sp != NULL) {
+ if (!(mi->mi_vfsp->vfs_flag & VFS_UNMOUNTED)) {
+ max_msec_delay = sp->s_lease_time * 1000 / 2 -
+ (3 * sp->propagation_delay.tv_sec *
+ 1000);
}
+ mutex_exit(&sp->s_lock);
+ nfs4_server_rele(sp);
+ }
+ nfs_rw_exit(&mi->mi_recovlock);
+
+ max_msec_delay = MAX(max_msec_delay, nfs4_base_wait_time);
+ *tick_delay = MIN(drv_usectohz(max_msec_delay * 1000), *tick_delay * 2);
return (0);
}
-
void
nfs4_vnops_init(void)
{
}