[GFS2] Fix calculation of demote state
[cascardo/linux.git] / fs / gfs2 / glock.c
index b075f93..6b6ae45 100644 (file)
@@ -422,11 +422,11 @@ void gfs2_holder_uninit(struct gfs2_holder *gh)
 static void gfs2_holder_wake(struct gfs2_holder *gh)
 {
        clear_bit(HIF_WAIT, &gh->gh_iflags);
-       smp_mb();
+       smp_mb__after_clear_bit();
        wake_up_bit(&gh->gh_iflags, HIF_WAIT);
 }
 
-static int holder_wait(void *word)
+static int just_schedule(void *word)
 {
         schedule();
         return 0;
@@ -435,7 +435,20 @@ static int holder_wait(void *word)
 static void wait_on_holder(struct gfs2_holder *gh)
 {
        might_sleep();
-       wait_on_bit(&gh->gh_iflags, HIF_WAIT, holder_wait, TASK_UNINTERRUPTIBLE);
+       wait_on_bit(&gh->gh_iflags, HIF_WAIT, just_schedule, TASK_UNINTERRUPTIBLE);
+}
+
+static void gfs2_demote_wake(struct gfs2_glock *gl)
+{
+        clear_bit(GLF_DEMOTE, &gl->gl_flags);
+        smp_mb__after_clear_bit();
+        wake_up_bit(&gl->gl_flags, GLF_DEMOTE);
+}
+
+static void wait_on_demote(struct gfs2_glock *gl)
+{
+       might_sleep();
+       wait_on_bit(&gl->gl_flags, GLF_DEMOTE, just_schedule, TASK_UNINTERRUPTIBLE);
 }
 
 /**
@@ -528,16 +541,18 @@ static int rq_demote(struct gfs2_glock *gl)
 
        if (gl->gl_state == gl->gl_demote_state ||
            gl->gl_state == LM_ST_UNLOCKED) {
-               clear_bit(GLF_DEMOTE, &gl->gl_flags);
+               gfs2_demote_wake(gl);
                return 0;
        }
        set_bit(GLF_LOCK, &gl->gl_flags);
-       spin_unlock(&gl->gl_spin);
        if (gl->gl_demote_state == LM_ST_UNLOCKED ||
-           gl->gl_state != LM_ST_EXCLUSIVE)
+           gl->gl_state != LM_ST_EXCLUSIVE) {
+               spin_unlock(&gl->gl_spin);
                gfs2_glock_drop_th(gl);
-       else
+       } else {
+               spin_unlock(&gl->gl_spin);
                gfs2_glock_xmote_th(gl, NULL);
+       }
        spin_lock(&gl->gl_spin);
 
        return 0;
@@ -666,14 +681,25 @@ static void gfs2_glmutex_unlock(struct gfs2_glock *gl)
  * practise: LM_ST_SHARED and LM_ST_UNLOCKED
  */
 
-static void handle_callback(struct gfs2_glock *gl, unsigned int state)
+static void handle_callback(struct gfs2_glock *gl, unsigned int state, int remote)
 {
        spin_lock(&gl->gl_spin);
        if (test_and_set_bit(GLF_DEMOTE, &gl->gl_flags) == 0) {
                gl->gl_demote_state = state;
                gl->gl_demote_time = jiffies;
-       } else if (gl->gl_demote_state != LM_ST_UNLOCKED) {
-               gl->gl_demote_state = state;
+               if (remote && gl->gl_ops->go_type == LM_TYPE_IOPEN &&
+                   gl->gl_object) {
+                       struct inode *inode = igrab(gl->gl_object);
+                       spin_unlock(&gl->gl_spin);
+                       if (inode) {
+                               d_prune_aliases(inode);
+                               iput(inode);
+                       }
+                       return;
+               }
+       } else if (gl->gl_demote_state != LM_ST_UNLOCKED &&
+                       gl->gl_demote_state != state) {
+               gl->gl_demote_state = LM_ST_UNLOCKED;
        }
        spin_unlock(&gl->gl_spin);
 }
@@ -737,10 +763,20 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
 
        if (!gh) {
                gl->gl_stamp = jiffies;
-               if (ret & LM_OUT_CANCELED)
+               if (ret & LM_OUT_CANCELED) {
                        op_done = 0;
-               else
-                       clear_bit(GLF_DEMOTE, &gl->gl_flags);
+               } else {
+                       spin_lock(&gl->gl_spin);
+                       if (gl->gl_state != gl->gl_demote_state) {
+                               gl->gl_req_bh = NULL;
+                               spin_unlock(&gl->gl_spin);
+                               gfs2_glock_drop_th(gl);
+                               gfs2_glock_put(gl);
+                               return;
+                       }
+                       gfs2_demote_wake(gl);
+                       spin_unlock(&gl->gl_spin);
+               }
        } else {
                spin_lock(&gl->gl_spin);
                list_del_init(&gh->gh_list);
@@ -794,7 +830,7 @@ out:
  *
  */
 
-void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh)
+static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh)
 {
        struct gfs2_sbd *sdp = gl->gl_sbd;
        int flags = gh ? gh->gh_flags : 0;
@@ -848,7 +884,7 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
        gfs2_assert_warn(sdp, !ret);
 
        state_change(gl, LM_ST_UNLOCKED);
-       clear_bit(GLF_DEMOTE, &gl->gl_flags);
+       gfs2_demote_wake(gl);
 
        if (glops->go_inval)
                glops->go_inval(gl, DIO_METADATA);
@@ -1174,7 +1210,7 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
        const struct gfs2_glock_operations *glops = gl->gl_ops;
 
        if (gh->gh_flags & GL_NOCACHE)
-               handle_callback(gl, LM_ST_UNLOCKED);
+               handle_callback(gl, LM_ST_UNLOCKED, 0);
 
        gfs2_glmutex_lock(gl);
 
@@ -1196,6 +1232,13 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
        spin_unlock(&gl->gl_spin);
 }
 
+void gfs2_glock_dq_wait(struct gfs2_holder *gh)
+{
+       struct gfs2_glock *gl = gh->gh_gl;
+       gfs2_glock_dq(gh);
+       wait_on_demote(gl);
+}
+
 /**
  * gfs2_glock_dq_uninit - dequeue a holder from a glock and initialize it
  * @gh: the holder structure
@@ -1297,10 +1340,6 @@ static int nq_m_sync(unsigned int num_gh, struct gfs2_holder *ghs,
  * @num_gh: the number of structures
  * @ghs: an array of struct gfs2_holder structures
  *
- * Figure out how big an impact this function has.  Either:
- * 1) Replace this code with code that calls gfs2_glock_prefetch()
- * 2) Forget async stuff and just call nq_m_sync()
- * 3) Leave it like it is
  *
  * Returns: 0 on success (all glocks acquired),
  *          errno on failure (no glocks acquired)
@@ -1308,62 +1347,28 @@ static int nq_m_sync(unsigned int num_gh, struct gfs2_holder *ghs,
 
 int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs)
 {
-       int *e;
-       unsigned int x;
-       int borked = 0, serious = 0;
+       struct gfs2_holder *tmp[4];
+       struct gfs2_holder **pph = tmp;
        int error = 0;
 
-       if (!num_gh)
+       switch(num_gh) {
+       case 0:
                return 0;
-
-       if (num_gh == 1) {
+       case 1:
                ghs->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC);
                return gfs2_glock_nq(ghs);
-       }
-
-       e = kcalloc(num_gh, sizeof(struct gfs2_holder *), GFP_KERNEL);
-       if (!e)
-               return -ENOMEM;
-
-       for (x = 0; x < num_gh; x++) {
-               ghs[x].gh_flags |= LM_FLAG_TRY | GL_ASYNC;
-               error = gfs2_glock_nq(&ghs[x]);
-               if (error) {
-                       borked = 1;
-                       serious = error;
-                       num_gh = x;
+       default:
+               if (num_gh <= 4)
                        break;
-               }
+               pph = kmalloc(num_gh * sizeof(struct gfs2_holder *), GFP_NOFS);
+               if (!pph)
+                       return -ENOMEM;
        }
 
-       for (x = 0; x < num_gh; x++) {
-               error = e[x] = glock_wait_internal(&ghs[x]);
-               if (error) {
-                       borked = 1;
-                       if (error != GLR_TRYFAILED && error != GLR_CANCELED)
-                               serious = error;
-               }
-       }
-
-       if (!borked) {
-               kfree(e);
-               return 0;
-       }
-
-       for (x = 0; x < num_gh; x++)
-               if (!e[x])
-                       gfs2_glock_dq(&ghs[x]);
-
-       if (serious)
-               error = serious;
-       else {
-               for (x = 0; x < num_gh; x++)
-                       gfs2_holder_reinit(ghs[x].gh_state, ghs[x].gh_flags,
-                                         &ghs[x]);
-               error = nq_m_sync(num_gh, ghs, (struct gfs2_holder **)e);
-       }
+       error = nq_m_sync(num_gh, ghs, pph);
 
-       kfree(e);
+       if (pph != tmp)
+               kfree(pph);
 
        return error;
 }
@@ -1456,7 +1461,7 @@ static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name,
        if (!gl)
                return;
 
-       handle_callback(gl, state);
+       handle_callback(gl, state, 1);
 
        spin_lock(&gl->gl_spin);
        run_queue(gl);
@@ -1596,7 +1601,7 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp)
        if (gfs2_glmutex_trylock(gl)) {
                if (list_empty(&gl->gl_holders) &&
                    gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl))
-                       handle_callback(gl, LM_ST_UNLOCKED);
+                       handle_callback(gl, LM_ST_UNLOCKED, 0);
                gfs2_glmutex_unlock(gl);
        }
 
@@ -1709,7 +1714,7 @@ static void clear_glock(struct gfs2_glock *gl)
        if (gfs2_glmutex_trylock(gl)) {
                if (list_empty(&gl->gl_holders) &&
                    gl->gl_state != LM_ST_UNLOCKED)
-                       handle_callback(gl, LM_ST_UNLOCKED);
+                       handle_callback(gl, LM_ST_UNLOCKED, 0);
                gfs2_glmutex_unlock(gl);
        }
 }
@@ -1763,22 +1768,10 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait)
 static void gfs2_print_symbol(struct glock_iter *gi, const char *fmt,
                               unsigned long address)
 {
-/* when sprint_symbol becomes available in the new kernel, replace this */
-/* function with:
        char buffer[KSYM_SYMBOL_LEN];
 
        sprint_symbol(buffer, address);
        print_dbg(gi, fmt, buffer);
-*/
-       char buffer[256];
-
-       if (gi) {
-               memset(buffer, 0, sizeof(buffer));
-               sprintf(buffer, "%p", address);
-               print_dbg(gi, fmt, buffer);
-       }
-       else
-               print_symbol(fmt, address);
 }
 
 /**
@@ -1835,7 +1828,8 @@ static int dump_inode(struct glock_iter *gi, struct gfs2_inode *ip)
 
        print_dbg(gi, "  Inode:\n");
        print_dbg(gi, "    num = %llu/%llu\n",
-                   ip->i_num.no_formal_ino, ip->i_num.no_addr);
+                 (unsigned long long)ip->i_no_formal_ino,
+                 (unsigned long long)ip->i_no_addr);
        print_dbg(gi, "    type = %u\n", IF2DT(ip->i_inode.i_mode));
        print_dbg(gi, "    i_flags =");
        for (x = 0; x < 32; x++)
@@ -1921,8 +1915,8 @@ static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl)
        }
        if (test_bit(GLF_DEMOTE, &gl->gl_flags)) {
                print_dbg(gi, "  Demotion req to state %u (%llu uS ago)\n",
-                         gl->gl_demote_state,
-                         (u64)(jiffies - gl->gl_demote_time)*(1000000/HZ));
+                         gl->gl_demote_state, (unsigned long long)
+                         (jiffies - gl->gl_demote_time)*(1000000/HZ));
        }
        if (gl->gl_ops == &gfs2_inode_glops && gl->gl_object) {
                if (!test_bit(GLF_LOCK, &gl->gl_flags) &&
@@ -2146,11 +2140,14 @@ static const struct file_operations gfs2_debug_fops = {
 
 int gfs2_create_debugfs_file(struct gfs2_sbd *sdp)
 {
-       sdp->debugfs_dentry = debugfs_create_file(sdp->sd_table_name,
-                                                 S_IFREG | S_IRUGO,
-                                                 gfs2_root, sdp,
-                                                 &gfs2_debug_fops);
-       if (!sdp->debugfs_dentry)
+       sdp->debugfs_dir = debugfs_create_dir(sdp->sd_table_name, gfs2_root);
+       if (!sdp->debugfs_dir)
+               return -ENOMEM;
+       sdp->debugfs_dentry_glocks = debugfs_create_file("glocks",
+                                                        S_IFREG | S_IRUGO,
+                                                        sdp->debugfs_dir, sdp,
+                                                        &gfs2_debug_fops);
+       if (!sdp->debugfs_dentry_glocks)
                return -ENOMEM;
 
        return 0;
@@ -2158,8 +2155,14 @@ int gfs2_create_debugfs_file(struct gfs2_sbd *sdp)
 
 void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp)
 {
-       if (sdp && sdp->debugfs_dentry)
-               debugfs_remove(sdp->debugfs_dentry);
+       if (sdp && sdp->debugfs_dir) {
+               if (sdp->debugfs_dentry_glocks) {
+                       debugfs_remove(sdp->debugfs_dentry_glocks);
+                       sdp->debugfs_dentry_glocks = NULL;
+               }
+               debugfs_remove(sdp->debugfs_dir);
+               sdp->debugfs_dir = NULL;
+       }
 }
 
 int gfs2_register_debugfs(void)
@@ -2171,4 +2174,5 @@ int gfs2_register_debugfs(void)
 void gfs2_unregister_debugfs(void)
 {
        debugfs_remove(gfs2_root);
+       gfs2_root = NULL;
 }