/*
* Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
- * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
#include <asm/uaccess.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
-#include <linux/module.h>
-#include <linux/kallsyms.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/workqueue.h>
+#include <linux/jiffies.h>
#include "gfs2.h"
#include "incore.h"
int hash; /* hash bucket index */
struct gfs2_sbd *sdp; /* incore superblock */
struct gfs2_glock *gl; /* current glock struct */
- struct hlist_head *hb_list; /* current hash bucket ptr */
struct seq_file *seq; /* sequence file for debugfs */
char string[512]; /* scratch space */
};
static int dump_glock(struct glock_iter *gi, struct gfs2_glock *gl);
static void gfs2_glock_xmote_th(struct gfs2_glock *gl, struct gfs2_holder *gh);
static void gfs2_glock_drop_th(struct gfs2_glock *gl);
+static void run_queue(struct gfs2_glock *gl);
+
static DECLARE_RWSEM(gfs2_umount_flush_sem);
static struct dentry *gfs2_root;
+static struct task_struct *scand_process;
+static unsigned int scand_secs = 5;
+static struct workqueue_struct *glock_workqueue;
#define GFS2_GL_HASH_SHIFT 15
#define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT)
if (atomic_dec_and_test(&gl->gl_ref)) {
hlist_del(&gl->gl_list);
write_unlock(gl_lock_addr(gl->gl_hash));
- BUG_ON(spin_is_locked(&gl->gl_spin));
gfs2_assert(sdp, gl->gl_state == LM_ST_UNLOCKED);
gfs2_assert(sdp, list_empty(&gl->gl_reclaim));
gfs2_assert(sdp, list_empty(&gl->gl_holders));
return gl;
}
+static void glock_work_func(struct work_struct *work)
+{
+ struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_work.work);
+
+ spin_lock(&gl->gl_spin);
+ if (test_and_clear_bit(GLF_PENDING_DEMOTE, &gl->gl_flags))
+ set_bit(GLF_DEMOTE, &gl->gl_flags);
+ run_queue(gl);
+ spin_unlock(&gl->gl_spin);
+ gfs2_glock_put(gl);
+}
+
/**
* gfs2_glock_get() - Get a glock, or create one if one doesn't exist
* @sdp: The GFS2 superblock
gl->gl_name = name;
atomic_set(&gl->gl_ref, 1);
gl->gl_state = LM_ST_UNLOCKED;
+ gl->gl_demote_state = LM_ST_EXCLUSIVE;
gl->gl_hash = hash;
- gl->gl_owner_pid = 0;
+ gl->gl_owner_pid = NULL;
gl->gl_ip = 0;
gl->gl_ops = glops;
gl->gl_req_gh = NULL;
gl->gl_req_bh = NULL;
gl->gl_vn = 0;
gl->gl_stamp = jiffies;
+ gl->gl_tchange = jiffies;
gl->gl_object = NULL;
gl->gl_sbd = sdp;
gl->gl_aspace = NULL;
- lops_init_le(&gl->gl_le, &gfs2_glock_lops);
+ INIT_DELAYED_WORK(&gl->gl_work, glock_work_func);
/* If this glock protects actual on-disk data or metadata blocks,
create a VFS inode to manage the pages/buffers holding them. */
INIT_LIST_HEAD(&gh->gh_list);
gh->gh_gl = gl;
gh->gh_ip = (unsigned long)__builtin_return_address(0);
- gh->gh_owner_pid = current->pid;
+ gh->gh_owner_pid = get_pid(task_pid(current));
gh->gh_state = state;
gh->gh_flags = flags;
gh->gh_error = 0;
void gfs2_holder_uninit(struct gfs2_holder *gh)
{
+ put_pid(gh->gh_owner_pid);
gfs2_glock_put(gh->gh_gl);
gh->gh_gl = NULL;
gh->gh_ip = 0;
static void gfs2_demote_wake(struct gfs2_glock *gl)
{
+ gl->gl_demote_state = LM_ST_EXCLUSIVE;
clear_bit(GLF_DEMOTE, &gl->gl_flags);
smp_mb__after_clear_bit();
wake_up_bit(&gl->gl_flags, GLF_DEMOTE);
static int rq_promote(struct gfs2_holder *gh)
{
struct gfs2_glock *gl = gh->gh_gl;
- struct gfs2_sbd *sdp = gl->gl_sbd;
if (!relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
if (list_empty(&gl->gl_holders)) {
gl->gl_req_gh = gh;
set_bit(GLF_LOCK, &gl->gl_flags);
spin_unlock(&gl->gl_spin);
-
- if (atomic_read(&sdp->sd_reclaim_count) >
- gfs2_tune_get(sdp, gt_reclaim_limit) &&
- !(gh->gh_flags & LM_FLAG_PRIORITY)) {
- gfs2_reclaim_glock(sdp);
- gfs2_reclaim_glock(sdp);
- }
-
gfs2_glock_xmote_th(gh->gh_gl, gh);
spin_lock(&gl->gl_spin);
}
gfs2_demote_wake(gl);
return 0;
}
+
set_bit(GLF_LOCK, &gl->gl_flags);
- spin_unlock(&gl->gl_spin);
+ set_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags);
+
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);
+ clear_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags);
return 0;
}
if (!list_empty(&gl->gl_waiters1)) {
gh = list_entry(gl->gl_waiters1.next,
struct gfs2_holder, gh_list);
-
- if (test_bit(HIF_MUTEX, &gh->gh_iflags))
- blocked = rq_mutex(gh);
- else
- gfs2_assert_warn(gl->gl_sbd, 0);
-
+ blocked = rq_mutex(gh);
} else if (test_bit(GLF_DEMOTE, &gl->gl_flags)) {
blocked = rq_demote(gl);
+ if (gl->gl_waiters2 && !blocked) {
+ set_bit(GLF_DEMOTE, &gl->gl_flags);
+ gl->gl_demote_state = LM_ST_UNLOCKED;
+ }
+ gl->gl_waiters2 = 0;
} else if (!list_empty(&gl->gl_waiters3)) {
gh = list_entry(gl->gl_waiters3.next,
struct gfs2_holder, gh_list);
-
- if (test_bit(HIF_PROMOTE, &gh->gh_iflags))
- blocked = rq_promote(gh);
- else
- gfs2_assert_warn(gl->gl_sbd, 0);
-
+ blocked = rq_promote(gh);
} else
break;
static void gfs2_glmutex_lock(struct gfs2_glock *gl)
{
- struct gfs2_holder gh;
-
- gfs2_holder_init(gl, 0, 0, &gh);
- set_bit(HIF_MUTEX, &gh.gh_iflags);
- if (test_and_set_bit(HIF_WAIT, &gh.gh_iflags))
- BUG();
-
spin_lock(&gl->gl_spin);
if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
+ struct gfs2_holder gh;
+
+ gfs2_holder_init(gl, 0, 0, &gh);
+ set_bit(HIF_WAIT, &gh.gh_iflags);
list_add_tail(&gh.gh_list, &gl->gl_waiters1);
+ spin_unlock(&gl->gl_spin);
+ wait_on_holder(&gh);
+ gfs2_holder_uninit(&gh);
} else {
- gl->gl_owner_pid = current->pid;
+ gl->gl_owner_pid = get_pid(task_pid(current));
gl->gl_ip = (unsigned long)__builtin_return_address(0);
- clear_bit(HIF_WAIT, &gh.gh_iflags);
- smp_mb();
- wake_up_bit(&gh.gh_iflags, HIF_WAIT);
+ spin_unlock(&gl->gl_spin);
}
- spin_unlock(&gl->gl_spin);
-
- wait_on_holder(&gh);
- gfs2_holder_uninit(&gh);
}
/**
if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
acquired = 0;
} else {
- gl->gl_owner_pid = current->pid;
+ gl->gl_owner_pid = get_pid(task_pid(current));
gl->gl_ip = (unsigned long)__builtin_return_address(0);
}
spin_unlock(&gl->gl_spin);
static void gfs2_glmutex_unlock(struct gfs2_glock *gl)
{
+ struct pid *pid;
+
spin_lock(&gl->gl_spin);
clear_bit(GLF_LOCK, &gl->gl_flags);
- gl->gl_owner_pid = 0;
+ pid = gl->gl_owner_pid;
+ gl->gl_owner_pid = NULL;
gl->gl_ip = 0;
run_queue(gl);
- BUG_ON(!spin_is_locked(&gl->gl_spin));
spin_unlock(&gl->gl_spin);
+
+ put_pid(pid);
}
/**
* practise: LM_ST_SHARED and LM_ST_UNLOCKED
*/
-static void handle_callback(struct gfs2_glock *gl, unsigned int state, int remote)
+static void handle_callback(struct gfs2_glock *gl, unsigned int state,
+ int remote, unsigned long delay)
{
+ int bit = delay ? GLF_PENDING_DEMOTE : GLF_DEMOTE;
+
spin_lock(&gl->gl_spin);
- if (test_and_set_bit(GLF_DEMOTE, &gl->gl_flags) == 0) {
+ set_bit(bit, &gl->gl_flags);
+ if (gl->gl_demote_state == LM_ST_EXCLUSIVE) {
gl->gl_demote_state = state;
gl->gl_demote_time = jiffies;
if (remote && gl->gl_ops->go_type == LM_TYPE_IOPEN &&
gl->gl_object) {
- struct inode *inode = igrab(gl->gl_object);
+ gfs2_glock_schedule_for_reclaim(gl);
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;
+ } else if (gl->gl_demote_state != LM_ST_UNLOCKED &&
+ gl->gl_demote_state != state) {
+ if (test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags))
+ gl->gl_waiters2 = 1;
+ else
+ gl->gl_demote_state = LM_ST_UNLOCKED;
}
spin_unlock(&gl->gl_spin);
}
}
gl->gl_state = new_state;
+ gl->gl_tchange = jiffies;
}
/**
if (!gh) {
gl->gl_stamp = jiffies;
- if (ret & LM_OUT_CANCELED)
+ if (ret & LM_OUT_CANCELED) {
op_done = 0;
- else
+ } 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);
gl->gl_req_gh = NULL;
gl->gl_req_bh = NULL;
clear_bit(GLF_LOCK, &gl->gl_flags);
- run_queue(gl);
spin_unlock(&gl->gl_spin);
}
*
*/
-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;
gfs2_assert_warn(sdp, !ret);
state_change(gl, LM_ST_UNLOCKED);
- gfs2_demote_wake(gl);
if (glops->go_inval)
glops->go_inval(gl, DIO_METADATA);
}
spin_lock(&gl->gl_spin);
+ gfs2_demote_wake(gl);
gl->gl_req_gh = NULL;
gl->gl_req_bh = NULL;
clear_bit(GLF_LOCK, &gl->gl_flags);
- run_queue(gl);
spin_unlock(&gl->gl_spin);
gfs2_glock_put(gl);
const struct gfs2_glock_operations *glops = gl->gl_ops;
unsigned int ret;
- if (glops->go_drop_th)
- glops->go_drop_th(gl);
+ if (glops->go_xmote_th)
+ glops->go_xmote_th(gl);
gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
}
static inline struct gfs2_holder *
-find_holder_by_owner(struct list_head *head, pid_t pid)
+find_holder_by_owner(struct list_head *head, struct pid *pid)
{
struct gfs2_holder *gh;
struct gfs2_glock *gl = gh->gh_gl;
struct gfs2_holder *existing;
- BUG_ON(!gh->gh_owner_pid);
+ BUG_ON(gh->gh_owner_pid == NULL);
if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags))
BUG();
- existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner_pid);
- if (existing) {
- print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
- printk(KERN_INFO "pid : %d\n", existing->gh_owner_pid);
- printk(KERN_INFO "lock type : %d lock state : %d\n",
- existing->gh_gl->gl_name.ln_type, existing->gh_gl->gl_state);
- print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
- printk(KERN_INFO "pid : %d\n", gh->gh_owner_pid);
- printk(KERN_INFO "lock type : %d lock state : %d\n",
- gl->gl_name.ln_type, gl->gl_state);
- BUG();
- }
-
- existing = find_holder_by_owner(&gl->gl_waiters3, gh->gh_owner_pid);
- if (existing) {
- print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
- print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
- BUG();
+ if (!(gh->gh_flags & GL_FLOCK)) {
+ existing = find_holder_by_owner(&gl->gl_holders,
+ gh->gh_owner_pid);
+ if (existing) {
+ print_symbol(KERN_WARNING "original: %s\n",
+ existing->gh_ip);
+ printk(KERN_INFO "pid : %d\n",
+ pid_nr(existing->gh_owner_pid));
+ printk(KERN_INFO "lock type : %d lock state : %d\n",
+ existing->gh_gl->gl_name.ln_type,
+ existing->gh_gl->gl_state);
+ print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
+ printk(KERN_INFO "pid : %d\n",
+ pid_nr(gh->gh_owner_pid));
+ printk(KERN_INFO "lock type : %d lock state : %d\n",
+ gl->gl_name.ln_type, gl->gl_state);
+ BUG();
+ }
+
+ existing = find_holder_by_owner(&gl->gl_waiters3,
+ gh->gh_owner_pid);
+ if (existing) {
+ print_symbol(KERN_WARNING "original: %s\n",
+ existing->gh_ip);
+ print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
+ BUG();
+ }
}
if (gh->gh_flags & LM_FLAG_PRIORITY)
return -EIO;
}
- set_bit(HIF_PROMOTE, &gh->gh_iflags);
-
spin_lock(&gl->gl_spin);
add_to_queue(gh);
run_queue(gl);
{
struct gfs2_glock *gl = gh->gh_gl;
const struct gfs2_glock_operations *glops = gl->gl_ops;
+ unsigned delay = 0;
if (gh->gh_flags & GL_NOCACHE)
- handle_callback(gl, LM_ST_UNLOCKED, 0);
+ handle_callback(gl, LM_ST_UNLOCKED, 0, 0);
gfs2_glmutex_lock(gl);
list_del_init(&gh->gh_list);
if (list_empty(&gl->gl_holders)) {
- spin_unlock(&gl->gl_spin);
-
- if (glops->go_unlock)
+ if (glops->go_unlock) {
+ spin_unlock(&gl->gl_spin);
glops->go_unlock(gh);
-
- spin_lock(&gl->gl_spin);
+ spin_lock(&gl->gl_spin);
+ }
gl->gl_stamp = jiffies;
}
clear_bit(GLF_LOCK, &gl->gl_flags);
- run_queue(gl);
spin_unlock(&gl->gl_spin);
+
+ gfs2_glock_hold(gl);
+ if (test_bit(GLF_PENDING_DEMOTE, &gl->gl_flags) &&
+ !test_bit(GLF_DEMOTE, &gl->gl_flags))
+ delay = gl->gl_ops->go_min_hold_time;
+ if (queue_delayed_work(glock_workqueue, &gl->gl_work, delay) == 0)
+ gfs2_glock_put(gl);
}
void gfs2_glock_dq_wait(struct gfs2_holder *gh)
unsigned int state)
{
struct gfs2_glock *gl;
+ unsigned long delay = 0;
+ unsigned long holdtime;
+ unsigned long now = jiffies;
gl = gfs2_glock_find(sdp, name);
if (!gl)
return;
- handle_callback(gl, state, 1);
+ holdtime = gl->gl_tchange + gl->gl_ops->go_min_hold_time;
+ if (time_before(now, holdtime))
+ delay = holdtime - now;
- spin_lock(&gl->gl_spin);
- run_queue(gl);
- spin_unlock(&gl->gl_spin);
-
- gfs2_glock_put(gl);
+ handle_callback(gl, state, 1, delay);
+ if (queue_delayed_work(glock_workqueue, &gl->gl_work, delay) == 0)
+ gfs2_glock_put(gl);
}
/**
return;
if (!gfs2_assert_warn(sdp, gl->gl_req_bh))
gl->gl_req_bh(gl, async->lc_ret);
- gfs2_glock_put(gl);
+ if (queue_delayed_work(glock_workqueue, &gl->gl_work, 0) == 0)
+ gfs2_glock_put(gl);
up_read(&gfs2_umount_flush_sem);
return;
}
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, 0);
+ handle_callback(gl, LM_ST_UNLOCKED, 0, 0);
gfs2_glmutex_unlock(gl);
}
goto out;
gl = list_entry(head->first, struct gfs2_glock, gl_list);
while(1) {
- if (gl->gl_sbd == sdp) {
+ if (!sdp || gl->gl_sbd == sdp) {
gfs2_glock_hold(gl);
read_unlock(gl_lock_addr(hash));
if (prev)
read_unlock(gl_lock_addr(hash));
if (prev)
gfs2_glock_put(prev);
+ cond_resched();
return has_entries;
}
gfs2_glock_schedule_for_reclaim(gl);
}
-/**
- * gfs2_scand_internal - Look for glocks and inodes to toss from memory
- * @sdp: the filesystem
- *
- */
-
-void gfs2_scand_internal(struct gfs2_sbd *sdp)
-{
- unsigned int x;
-
- for (x = 0; x < GFS2_GL_HASH_SIZE; x++)
- examine_bucket(scan_glock, sdp, x);
-}
-
/**
* clear_glock - look at a glock and see if we can free it from glock cache
* @gl: the glock to look at
if (gfs2_glmutex_trylock(gl)) {
if (list_empty(&gl->gl_holders) &&
gl->gl_state != LM_ST_UNLOCKED)
- handle_callback(gl, LM_ST_UNLOCKED, 0);
+ handle_callback(gl, LM_ST_UNLOCKED, 0, 0);
gfs2_glmutex_unlock(gl);
}
}
print_dbg(gi, " %s\n", str);
if (gh->gh_owner_pid) {
- print_dbg(gi, " owner = %ld ", (long)gh->gh_owner_pid);
- gh_owner = find_task_by_pid(gh->gh_owner_pid);
+ print_dbg(gi, " owner = %ld ",
+ (long)pid_nr(gh->gh_owner_pid));
+ gh_owner = pid_task(gh->gh_owner_pid, PIDTYPE_PID);
if (gh_owner)
print_dbg(gi, "(%s)\n", gh_owner->comm);
else
spin_lock(&gl->gl_spin);
- print_dbg(gi, "Glock 0x%p (%u, %llu)\n", gl, gl->gl_name.ln_type,
+ print_dbg(gi, "Glock 0x%p (%u, 0x%llx)\n", gl, gl->gl_name.ln_type,
(unsigned long long)gl->gl_name.ln_number);
print_dbg(gi, " gl_flags =");
for (x = 0; x < 32; x++) {
print_dbg(gi, " gl_ref = %d\n", atomic_read(&gl->gl_ref));
print_dbg(gi, " gl_state = %u\n", gl->gl_state);
if (gl->gl_owner_pid) {
- gl_owner = find_task_by_pid(gl->gl_owner_pid);
+ gl_owner = pid_task(gl->gl_owner_pid, PIDTYPE_PID);
if (gl_owner)
print_dbg(gi, " gl_owner = pid %d (%s)\n",
- gl->gl_owner_pid, gl_owner->comm);
+ pid_nr(gl->gl_owner_pid), gl_owner->comm);
else
print_dbg(gi, " gl_owner = %d (ended)\n",
- gl->gl_owner_pid);
+ pid_nr(gl->gl_owner_pid));
} else
print_dbg(gi, " gl_owner = -1\n");
print_dbg(gi, " gl_ip = %lu\n", gl->gl_ip);
print_dbg(gi, " req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no");
print_dbg(gi, " lvb_count = %d\n", atomic_read(&gl->gl_lvb_count));
print_dbg(gi, " object = %s\n", (gl->gl_object) ? "yes" : "no");
- print_dbg(gi, " le = %s\n",
- (list_empty(&gl->gl_le.le_list)) ? "no" : "yes");
print_dbg(gi, " reclaim = %s\n",
(list_empty(&gl->gl_reclaim)) ? "no" : "yes");
if (gl->gl_aspace)
return error;
}
+/**
+ * gfs2_scand - Look for cached glocks and inodes to toss from memory
+ * @sdp: Pointer to GFS2 superblock
+ *
+ * One of these daemons runs, finding candidates to add to sd_reclaim_list.
+ * See gfs2_glockd()
+ */
+
+static int gfs2_scand(void *data)
+{
+ unsigned x;
+ unsigned delay;
+
+ while (!kthread_should_stop()) {
+ for (x = 0; x < GFS2_GL_HASH_SIZE; x++)
+ examine_bucket(scan_glock, NULL, x);
+ if (freezing(current))
+ refrigerator();
+ delay = scand_secs;
+ if (delay < 1)
+ delay = 1;
+ schedule_timeout_interruptible(delay * HZ);
+ }
+
+ return 0;
+}
+
+
+
int __init gfs2_glock_init(void)
{
unsigned i;
rwlock_init(&gl_hash_locks[i]);
}
#endif
+
+ scand_process = kthread_run(gfs2_scand, NULL, "gfs2_scand");
+ if (IS_ERR(scand_process))
+ return PTR_ERR(scand_process);
+
+ glock_workqueue = create_workqueue("glock_workqueue");
+ if (IS_ERR(glock_workqueue)) {
+ kthread_stop(scand_process);
+ return PTR_ERR(glock_workqueue);
+ }
+
return 0;
}
+void gfs2_glock_exit(void)
+{
+ destroy_workqueue(glock_workqueue);
+ kthread_stop(scand_process);
+}
+
+module_param(scand_secs, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(scand_secs, "The number of seconds between scand runs");
+
static int gfs2_glock_iter_next(struct glock_iter *gi)
{
+ struct gfs2_glock *gl;
+
+restart:
read_lock(gl_lock_addr(gi->hash));
- while (1) {
- if (!gi->hb_list) { /* If we don't have a hash bucket yet */
- gi->hb_list = &gl_hash_table[gi->hash].hb_list;
- if (hlist_empty(gi->hb_list)) {
- read_unlock(gl_lock_addr(gi->hash));
- gi->hash++;
- read_lock(gl_lock_addr(gi->hash));
- gi->hb_list = NULL;
- if (gi->hash >= GFS2_GL_HASH_SIZE) {
- read_unlock(gl_lock_addr(gi->hash));
- return 1;
- }
- else
- continue;
- }
- if (!hlist_empty(gi->hb_list)) {
- gi->gl = list_entry(gi->hb_list->first,
- struct gfs2_glock,
- gl_list);
- }
- } else {
- if (gi->gl->gl_list.next == NULL) {
- read_unlock(gl_lock_addr(gi->hash));
- gi->hash++;
- read_lock(gl_lock_addr(gi->hash));
- gi->hb_list = NULL;
- continue;
- }
- gi->gl = list_entry(gi->gl->gl_list.next,
- struct gfs2_glock, gl_list);
- }
+ gl = gi->gl;
+ if (gl) {
+ gi->gl = hlist_entry(gl->gl_list.next,
+ struct gfs2_glock, gl_list);
if (gi->gl)
- break;
+ gfs2_glock_hold(gi->gl);
}
read_unlock(gl_lock_addr(gi->hash));
+ if (gl)
+ gfs2_glock_put(gl);
+ if (gl && gi->gl == NULL)
+ gi->hash++;
+ while(gi->gl == NULL) {
+ if (gi->hash >= GFS2_GL_HASH_SIZE)
+ return 1;
+ read_lock(gl_lock_addr(gi->hash));
+ gi->gl = hlist_entry(gl_hash_table[gi->hash].hb_list.first,
+ struct gfs2_glock, gl_list);
+ if (gi->gl)
+ gfs2_glock_hold(gi->gl);
+ read_unlock(gl_lock_addr(gi->hash));
+ gi->hash++;
+ }
+
+ if (gi->sdp != gi->gl->gl_sbd)
+ goto restart;
+
return 0;
}
static void gfs2_glock_iter_free(struct glock_iter *gi)
{
+ if (gi->gl)
+ gfs2_glock_put(gi->gl);
kfree(gi);
}
gi->sdp = sdp;
gi->hash = 0;
- gi->gl = NULL;
- gi->hb_list = NULL;
gi->seq = NULL;
+ gi->gl = NULL;
memset(gi->string, 0, sizeof(gi->string));
if (gfs2_glock_iter_next(gi)) {
if (!gi)
return NULL;
- while (n--) {
+ while(n--) {
if (gfs2_glock_iter_next(gi)) {
gfs2_glock_iter_free(gi);
return NULL;
static void gfs2_glock_seq_stop(struct seq_file *file, void *iter_ptr)
{
- /* nothing for now */
+ struct glock_iter *gi = iter_ptr;
+ if (gi)
+ gfs2_glock_iter_free(gi);
}
static int gfs2_glock_seq_show(struct seq_file *file, void *iter_ptr)
return 0;
}
-static struct seq_operations gfs2_glock_seq_ops = {
+static const struct seq_operations gfs2_glock_seq_ops = {
.start = gfs2_glock_seq_start,
.next = gfs2_glock_seq_next,
.stop = gfs2_glock_seq_stop,