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)
 {
 }