]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - fs/gfs2/glock.c
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[linux.git] / fs / gfs2 / glock.c
index e23fb8b7b020ef56f6bde4d93af0c48daa3a2005..0290a22ebccf56bf457fd811f4c37b5ddffce79e 100644 (file)
@@ -305,6 +305,11 @@ static void gfs2_holder_wake(struct gfs2_holder *gh)
        clear_bit(HIF_WAIT, &gh->gh_iflags);
        smp_mb__after_atomic();
        wake_up_bit(&gh->gh_iflags, HIF_WAIT);
+       if (gh->gh_flags & GL_ASYNC) {
+               struct gfs2_sbd *sdp = gh->gh_gl->gl_name.ln_sbd;
+
+               wake_up(&sdp->sd_async_glock_wait);
+       }
 }
 
 /**
@@ -931,6 +936,17 @@ void gfs2_holder_uninit(struct gfs2_holder *gh)
        gh->gh_ip = 0;
 }
 
+static void gfs2_glock_update_hold_time(struct gfs2_glock *gl,
+                                       unsigned long start_time)
+{
+       /* Have we waited longer that a second? */
+       if (time_after(jiffies, start_time + HZ)) {
+               /* Lengthen the minimum hold time. */
+               gl->gl_hold_time = min(gl->gl_hold_time + GL_GLOCK_HOLD_INCR,
+                                      GL_GLOCK_MAX_HOLD);
+       }
+}
+
 /**
  * gfs2_glock_wait - wait on a glock acquisition
  * @gh: the glock holder
@@ -940,18 +956,99 @@ void gfs2_holder_uninit(struct gfs2_holder *gh)
 
 int gfs2_glock_wait(struct gfs2_holder *gh)
 {
-       unsigned long time1 = jiffies;
+       unsigned long start_time = jiffies;
 
        might_sleep();
        wait_on_bit(&gh->gh_iflags, HIF_WAIT, TASK_UNINTERRUPTIBLE);
-       if (time_after(jiffies, time1 + HZ)) /* have we waited > a second? */
-               /* Lengthen the minimum hold time. */
-               gh->gh_gl->gl_hold_time = min(gh->gh_gl->gl_hold_time +
-                                             GL_GLOCK_HOLD_INCR,
-                                             GL_GLOCK_MAX_HOLD);
+       gfs2_glock_update_hold_time(gh->gh_gl, start_time);
        return gh->gh_error;
 }
 
+static int glocks_pending(unsigned int num_gh, struct gfs2_holder *ghs)
+{
+       int i;
+
+       for (i = 0; i < num_gh; i++)
+               if (test_bit(HIF_WAIT, &ghs[i].gh_iflags))
+                       return 1;
+       return 0;
+}
+
+/**
+ * gfs2_glock_async_wait - wait on multiple asynchronous glock acquisitions
+ * @num_gh: the number of holders in the array
+ * @ghs: the glock holder array
+ *
+ * Returns: 0 on success, meaning all glocks have been granted and are held.
+ *          -ESTALE if the request timed out, meaning all glocks were released,
+ *          and the caller should retry the operation.
+ */
+
+int gfs2_glock_async_wait(unsigned int num_gh, struct gfs2_holder *ghs)
+{
+       struct gfs2_sbd *sdp = ghs[0].gh_gl->gl_name.ln_sbd;
+       int i, ret = 0, timeout = 0;
+       unsigned long start_time = jiffies;
+       bool keep_waiting;
+
+       might_sleep();
+       /*
+        * Total up the (minimum hold time * 2) of all glocks and use that to
+        * determine the max amount of time we should wait.
+        */
+       for (i = 0; i < num_gh; i++)
+               timeout += ghs[i].gh_gl->gl_hold_time << 1;
+
+wait_for_dlm:
+       if (!wait_event_timeout(sdp->sd_async_glock_wait,
+                               !glocks_pending(num_gh, ghs), timeout))
+               ret = -ESTALE; /* request timed out. */
+
+       /*
+        * If dlm granted all our requests, we need to adjust the glock
+        * minimum hold time values according to how long we waited.
+        *
+        * If our request timed out, we need to repeatedly release any held
+        * glocks we acquired thus far to allow dlm to acquire the remaining
+        * glocks without deadlocking.  We cannot currently cancel outstanding
+        * glock acquisitions.
+        *
+        * The HIF_WAIT bit tells us which requests still need a response from
+        * dlm.
+        *
+        * If dlm sent us any errors, we return the first error we find.
+        */
+       keep_waiting = false;
+       for (i = 0; i < num_gh; i++) {
+               /* Skip holders we have already dequeued below. */
+               if (!gfs2_holder_queued(&ghs[i]))
+                       continue;
+               /* Skip holders with a pending DLM response. */
+               if (test_bit(HIF_WAIT, &ghs[i].gh_iflags)) {
+                       keep_waiting = true;
+                       continue;
+               }
+
+               if (test_bit(HIF_HOLDER, &ghs[i].gh_iflags)) {
+                       if (ret == -ESTALE)
+                               gfs2_glock_dq(&ghs[i]);
+                       else
+                               gfs2_glock_update_hold_time(ghs[i].gh_gl,
+                                                           start_time);
+               }
+               if (!ret)
+                       ret = ghs[i].gh_error;
+       }
+
+       if (keep_waiting)
+               goto wait_for_dlm;
+
+       /*
+        * At this point, we've either acquired all locks or released them all.
+        */
+       return ret;
+}
+
 /**
  * handle_callback - process a demote request
  * @gl: the glock
@@ -1018,9 +1115,9 @@ __acquires(&gl->gl_lockref.lock)
        struct gfs2_holder *gh2;
        int try_futile = 0;
 
-       BUG_ON(gh->gh_owner_pid == NULL);
+       GLOCK_BUG_ON(gl, gh->gh_owner_pid == NULL);
        if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags))
-               BUG();
+               GLOCK_BUG_ON(gl, true);
 
        if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) {
                if (test_bit(GLF_LOCK, &gl->gl_flags))
@@ -1788,8 +1885,8 @@ void gfs2_dump_glock(struct seq_file *seq, struct gfs2_glock *gl, bool fsid)
        unsigned long long dtime;
        const struct gfs2_holder *gh;
        char gflags_buf[32];
-       char fs_id_buf[GFS2_FSNAME_LEN + 3 * sizeof(int) + 2];
        struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
+       char fs_id_buf[sizeof(sdp->sd_fsname) + 7];
 
        memset(fs_id_buf, 0, sizeof(fs_id_buf));
        if (fsid && sdp) /* safety precaution */