Commit 9518ae6e authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull gfs2 updates from Andreas Gruenbacher:

 - Properly fix the glock shrinker this time: it broke in commit "gfs2:
   Make glock lru list scanning safer" and commit "gfs2: fix glock
   shrinker ref issues" wasn't actually enough to fix it

 - On unmount, keep glocks around long enough that no more dlm callbacks
   can occur on them

 - Some more folio conversion patches from Matthew Wilcox

 - Lots of other smaller fixes and cleanups

* tag 'gfs2-for-v6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2: (27 commits)
  gfs2: make timeout values more explicit
  gfs2: Convert gfs2_aspace_writepage() to use a folio
  gfs2: Add a migrate_folio operation for journalled files
  gfs2: Simplify gfs2_read_super
  gfs2: Convert gfs2_page_mkwrite() to use a folio
  gfs2: gfs2_freeze_unlock cleanup
  gfs2: Remove and replace gfs2_glock_queue_work
  gfs2: do_xmote fixes
  gfs2: finish_xmote cleanup
  gfs2: Unlock fewer glocks on unmount
  gfs2: Fix potential glock use-after-free on unmount
  gfs2: Remove ill-placed consistency check
  gfs2: Fix lru_count accounting
  gfs2: Fix "Make glock lru list scanning safer"
  Revert "gfs2: fix glock shrinker ref issues"
  gfs2: Fix "ignore unlock failures after withdraw"
  gfs2: Get rid of unnecessary test_and_set_bit
  gfs2: Don't set GLF_LOCK in gfs2_dispose_glock_lru
  gfs2: Replace gfs2_glock_queue_put with gfs2_glock_put_async
  gfs2: Get rid of gfs2_glock_queue_put in signal_our_withdraw
  ...
parents 6fffab66 c1c53c26
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -116,8 +116,7 @@ static int gfs2_write_jdata_folio(struct folio *folio,
 * @folio: The folio to write
 * @wbc: The writeback control
 *
 * This is shared between writepage and writepages and implements the
 * core of the writepage operation. If a transaction is required then
 * Implements the core of write back. If a transaction is required then
 * the checked flag will have been set and the transaction will have
 * already been started before this is called.
 */
@@ -755,6 +754,7 @@ static const struct address_space_operations gfs2_jdata_aops = {
	.readahead = gfs2_readahead,
	.dirty_folio = jdata_dirty_folio,
	.bmap = gfs2_bmap,
	.migrate_folio = buffer_migrate_folio,
	.invalidate_folio = gfs2_invalidate_folio,
	.release_folio = gfs2_release_folio,
	.is_partially_uptodate = block_is_partially_uptodate,
+17 −14
Original line number Diff line number Diff line
@@ -562,15 +562,18 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, void *buf,
	int ret = 0;

	ret = gfs2_dirent_offset(GFS2_SB(inode), buf);
	if (ret < 0)
		goto consist_inode;

	if (ret < 0) {
		gfs2_consist_inode(GFS2_I(inode));
		return ERR_PTR(-EIO);
	}
	offset = ret;
	prev = NULL;
	dent = buf + offset;
	size = be16_to_cpu(dent->de_rec_len);
	if (gfs2_check_dirent(GFS2_SB(inode), dent, offset, size, len, 1))
		goto consist_inode;
	if (gfs2_check_dirent(GFS2_SB(inode), dent, offset, size, len, 1)) {
		gfs2_consist_inode(GFS2_I(inode));
		return ERR_PTR(-EIO);
	}
	do {
		ret = scan(dent, name, opaque);
		if (ret)
@@ -582,8 +585,10 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, void *buf,
		dent = buf + offset;
		size = be16_to_cpu(dent->de_rec_len);
		if (gfs2_check_dirent(GFS2_SB(inode), dent, offset, size,
				      len, 0))
			goto consist_inode;
				      len, 0)) {
			gfs2_consist_inode(GFS2_I(inode));
			return ERR_PTR(-EIO);
		}
	} while(1);

	switch(ret) {
@@ -597,10 +602,6 @@ static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, void *buf,
		BUG_ON(ret > 0);
		return ERR_PTR(ret);
	}

consist_inode:
	gfs2_consist_inode(GFS2_I(inode));
	return ERR_PTR(-EIO);
}

static int dirent_check_reclen(struct gfs2_inode *dip,
@@ -609,14 +610,16 @@ static int dirent_check_reclen(struct gfs2_inode *dip,
	const void *ptr = d;
	u16 rec_len = be16_to_cpu(d->de_rec_len);

	if (unlikely(rec_len < sizeof(struct gfs2_dirent)))
		goto broken;
	if (unlikely(rec_len < sizeof(struct gfs2_dirent))) {
		gfs2_consist_inode(dip);
		return -EIO;
	}
	ptr += rec_len;
	if (ptr < end_p)
		return rec_len;
	if (ptr == end_p)
		return -ENOENT;
broken:

	gfs2_consist_inode(dip);
	return -EIO;
}
+30 −29
Original line number Diff line number Diff line
@@ -376,23 +376,23 @@ static void gfs2_size_hint(struct file *filep, loff_t offset, size_t size)
}

/**
 * gfs2_allocate_page_backing - Allocate blocks for a write fault
 * @page: The (locked) page to allocate backing for
 * gfs2_allocate_folio_backing - Allocate blocks for a write fault
 * @folio: The (locked) folio to allocate backing for
 * @length: Size of the allocation
 *
 * We try to allocate all the blocks required for the page in one go.  This
 * We try to allocate all the blocks required for the folio in one go.  This
 * might fail for various reasons, so we keep trying until all the blocks to
 * back this page are allocated.  If some of the blocks are already allocated,
 * back this folio are allocated.  If some of the blocks are already allocated,
 * that is ok too.
 */
static int gfs2_allocate_page_backing(struct page *page, unsigned int length)
static int gfs2_allocate_folio_backing(struct folio *folio, size_t length)
{
	u64 pos = page_offset(page);
	u64 pos = folio_pos(folio);

	do {
		struct iomap iomap = { };

		if (gfs2_iomap_alloc(page->mapping->host, pos, length, &iomap))
		if (gfs2_iomap_alloc(folio->mapping->host, pos, length, &iomap))
			return -EIO;

		if (length < iomap.length)
@@ -414,16 +414,16 @@ static int gfs2_allocate_page_backing(struct page *page, unsigned int length)

static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
{
	struct page *page = vmf->page;
	struct folio *folio = page_folio(vmf->page);
	struct inode *inode = file_inode(vmf->vma->vm_file);
	struct gfs2_inode *ip = GFS2_I(inode);
	struct gfs2_sbd *sdp = GFS2_SB(inode);
	struct gfs2_alloc_parms ap = {};
	u64 offset = page_offset(page);
	u64 pos = folio_pos(folio);
	unsigned int data_blocks, ind_blocks, rblocks;
	vm_fault_t ret = VM_FAULT_LOCKED;
	struct gfs2_holder gh;
	unsigned int length;
	size_t length;
	loff_t size;
	int err;

@@ -436,23 +436,23 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
		goto out_uninit;
	}

	/* Check page index against inode size */
	/* Check folio index against inode size */
	size = i_size_read(inode);
	if (offset >= size) {
	if (pos >= size) {
		ret = VM_FAULT_SIGBUS;
		goto out_unlock;
	}

	/* Update file times before taking page lock */
	/* Update file times before taking folio lock */
	file_update_time(vmf->vma->vm_file);

	/* page is wholly or partially inside EOF */
	if (size - offset < PAGE_SIZE)
		length = size - offset;
	/* folio is wholly or partially inside EOF */
	if (size - pos < folio_size(folio))
		length = size - pos;
	else
		length = PAGE_SIZE;
		length = folio_size(folio);

	gfs2_size_hint(vmf->vma->vm_file, offset, length);
	gfs2_size_hint(vmf->vma->vm_file, pos, length);

	set_bit(GLF_DIRTY, &ip->i_gl->gl_flags);
	set_bit(GIF_SW_PAGED, &ip->i_flags);
@@ -463,11 +463,12 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
	 */

	if (!gfs2_is_stuffed(ip) &&
	    !gfs2_write_alloc_required(ip, offset, length)) {
		lock_page(page);
		if (!PageUptodate(page) || page->mapping != inode->i_mapping) {
	    !gfs2_write_alloc_required(ip, pos, length)) {
		folio_lock(folio);
		if (!folio_test_uptodate(folio) ||
		    folio->mapping != inode->i_mapping) {
			ret = VM_FAULT_NOPAGE;
			unlock_page(page);
			folio_unlock(folio);
		}
		goto out_unlock;
	}
@@ -504,7 +505,7 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
		goto out_trans_fail;
	}

	/* Unstuff, if required, and allocate backing blocks for page */
	/* Unstuff, if required, and allocate backing blocks for folio */
	if (gfs2_is_stuffed(ip)) {
		err = gfs2_unstuff_dinode(ip);
		if (err) {
@@ -513,22 +514,22 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
		}
	}

	lock_page(page);
	folio_lock(folio);
	/* If truncated, we must retry the operation, we may have raced
	 * with the glock demotion code.
	 */
	if (!PageUptodate(page) || page->mapping != inode->i_mapping) {
	if (!folio_test_uptodate(folio) || folio->mapping != inode->i_mapping) {
		ret = VM_FAULT_NOPAGE;
		goto out_page_locked;
	}

	err = gfs2_allocate_page_backing(page, length);
	err = gfs2_allocate_folio_backing(folio, length);
	if (err)
		ret = vmf_fs_error(err);

out_page_locked:
	if (ret != VM_FAULT_LOCKED)
		unlock_page(page);
		folio_unlock(folio);
out_trans_end:
	gfs2_trans_end(sdp);
out_trans_fail:
@@ -540,8 +541,8 @@ static vm_fault_t gfs2_page_mkwrite(struct vm_fault *vmf)
out_uninit:
	gfs2_holder_uninit(&gh);
	if (ret == VM_FAULT_LOCKED) {
		set_page_dirty(page);
		wait_for_stable_page(page);
		folio_mark_dirty(folio);
		folio_wait_stable(folio);
	}
	sb_end_pagefault(inode->i_sb);
	return ret;
+117 −75
Original line number Diff line number Diff line
@@ -166,19 +166,45 @@ static bool glock_blocked_by_withdraw(struct gfs2_glock *gl)
	return true;
}

void gfs2_glock_free(struct gfs2_glock *gl)
static void __gfs2_glock_free(struct gfs2_glock *gl)
{
	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;

	gfs2_glock_assert_withdraw(gl, atomic_read(&gl->gl_revokes) == 0);
	rhashtable_remove_fast(&gl_hash_table, &gl->gl_node, ht_parms);
	smp_mb();
	wake_up_glock(gl);
	call_rcu(&gl->gl_rcu, gfs2_glock_dealloc);
}

void gfs2_glock_free(struct gfs2_glock *gl) {
	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;

	__gfs2_glock_free(gl);
	if (atomic_dec_and_test(&sdp->sd_glock_disposal))
		wake_up(&sdp->sd_kill_wait);
}

void gfs2_glock_free_later(struct gfs2_glock *gl) {
	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;

	spin_lock(&lru_lock);
	list_add(&gl->gl_lru, &sdp->sd_dead_glocks);
	spin_unlock(&lru_lock);
	if (atomic_dec_and_test(&sdp->sd_glock_disposal))
		wake_up(&sdp->sd_kill_wait);
}

static void gfs2_free_dead_glocks(struct gfs2_sbd *sdp)
{
	struct list_head *list = &sdp->sd_dead_glocks;

	while(!list_empty(list)) {
		struct gfs2_glock *gl;

		gl = list_first_entry(list, struct gfs2_glock, gl_lru);
		list_del_init(&gl->gl_lru);
		__gfs2_glock_free(gl);
	}
}

/**
 * gfs2_glock_hold() - increment reference count on glock
 * @gl: The glock to hold
@@ -248,7 +274,7 @@ static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl)
 * Enqueue the glock on the work queue.  Passes one glock reference on to the
 * work queue.
 */
static void __gfs2_glock_queue_work(struct gfs2_glock *gl, unsigned long delay) {
static void gfs2_glock_queue_work(struct gfs2_glock *gl, unsigned long delay) {
	if (!queue_delayed_work(glock_workqueue, &gl->gl_work, delay)) {
		/*
		 * We are holding the lockref spinlock, and the work was still
@@ -261,12 +287,6 @@ static void __gfs2_glock_queue_work(struct gfs2_glock *gl, unsigned long delay)
	}
}

static void gfs2_glock_queue_work(struct gfs2_glock *gl, unsigned long delay) {
	spin_lock(&gl->gl_lockref.lock);
	__gfs2_glock_queue_work(gl, delay);
	spin_unlock(&gl->gl_lockref.lock);
}

static void __gfs2_glock_put(struct gfs2_glock *gl)
{
	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
@@ -285,14 +305,6 @@ static void __gfs2_glock_put(struct gfs2_glock *gl)
	sdp->sd_lockstruct.ls_ops->lm_put_lock(gl);
}

/*
 * Cause the glock to be put in work queue context.
 */
void gfs2_glock_queue_put(struct gfs2_glock *gl)
{
	gfs2_glock_queue_work(gl, 0);
}

/**
 * gfs2_glock_put() - Decrement reference count on glock
 * @gl: The glock to put
@@ -307,6 +319,23 @@ void gfs2_glock_put(struct gfs2_glock *gl)
	__gfs2_glock_put(gl);
}

/*
 * gfs2_glock_put_async - Decrement reference count without sleeping
 * @gl: The glock to put
 *
 * Decrement the reference count on glock immediately unless it is the last
 * reference.  Defer putting the last reference to work queue context.
 */
void gfs2_glock_put_async(struct gfs2_glock *gl)
{
	if (lockref_put_or_lock(&gl->gl_lockref))
		return;

	GLOCK_BUG_ON(gl, gl->gl_lockref.count != 1);
	gfs2_glock_queue_work(gl, 0);
	spin_unlock(&gl->gl_lockref.lock);
}

/**
 * may_grant - check if it's ok to grant a new lock
 * @gl: The glock
@@ -591,7 +620,6 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
	struct gfs2_holder *gh;
	unsigned state = ret & LM_OUT_ST_MASK;

	spin_lock(&gl->gl_lockref.lock);
	trace_gfs2_glock_state_change(gl, state);
	state_change(gl, state);
	gh = find_first_waiter(gl);
@@ -639,7 +667,6 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
			       gl->gl_target, state);
			GLOCK_BUG_ON(gl, 1);
		}
		spin_unlock(&gl->gl_lockref.lock);
		return;
	}

@@ -662,7 +689,6 @@ static void finish_xmote(struct gfs2_glock *gl, unsigned int ret)
	}
out:
	clear_bit(GLF_LOCK, &gl->gl_flags);
	spin_unlock(&gl->gl_lockref.lock);
}

static bool is_system_glock(struct gfs2_glock *gl)
@@ -690,6 +716,7 @@ __acquires(&gl->gl_lockref.lock)
{
	const struct gfs2_glock_operations *glops = gl->gl_ops;
	struct gfs2_sbd *sdp = gl->gl_name.ln_sbd;
	struct lm_lockstruct *ls = &sdp->sd_lockstruct;
	unsigned int lck_flags = (unsigned int)(gh ? gh->gh_flags : 0);
	int ret;

@@ -718,6 +745,9 @@ __acquires(&gl->gl_lockref.lock)
	    (gl->gl_state == LM_ST_EXCLUSIVE) ||
	    (lck_flags & (LM_FLAG_TRY|LM_FLAG_TRY_1CB)))
		clear_bit(GLF_BLOCKING, &gl->gl_flags);
	if (!glops->go_inval && !glops->go_sync)
		goto skip_inval;

	spin_unlock(&gl->gl_lockref.lock);
	if (glops->go_sync) {
		ret = glops->go_sync(gl);
@@ -730,6 +760,7 @@ __acquires(&gl->gl_lockref.lock)
				fs_err(sdp, "Error %d syncing glock \n", ret);
				gfs2_dump_glock(NULL, gl, true);
			}
			spin_lock(&gl->gl_lockref.lock);
			goto skip_inval;
		}
	}
@@ -750,9 +781,10 @@ __acquires(&gl->gl_lockref.lock)
		glops->go_inval(gl, target == LM_ST_DEFERRED ? 0 : DIO_METADATA);
		clear_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags);
	}
	spin_lock(&gl->gl_lockref.lock);

skip_inval:
	gfs2_glock_hold(gl);
	gl->gl_lockref.count++;
	/*
	 * Check for an error encountered since we called go_sync and go_inval.
	 * If so, we can't withdraw from the glock code because the withdraw
@@ -795,31 +827,37 @@ __acquires(&gl->gl_lockref.lock)
			clear_bit(GLF_LOCK, &gl->gl_flags);
			clear_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags);
			gfs2_glock_queue_work(gl, GL_GLOCK_DFT_HOLD);
			goto out;
			return;
		} else {
			clear_bit(GLF_INVALIDATE_IN_PROGRESS, &gl->gl_flags);
		}
	}

	if (sdp->sd_lockstruct.ls_ops->lm_lock)	{
		/* lock_dlm */
		ret = sdp->sd_lockstruct.ls_ops->lm_lock(gl, target, lck_flags);
	if (ls->ls_ops->lm_lock) {
		spin_unlock(&gl->gl_lockref.lock);
		ret = ls->ls_ops->lm_lock(gl, target, lck_flags);
		spin_lock(&gl->gl_lockref.lock);

		if (ret == -EINVAL && gl->gl_target == LM_ST_UNLOCKED &&
		    target == LM_ST_UNLOCKED &&
		    test_bit(SDF_SKIP_DLM_UNLOCK, &sdp->sd_flags)) {
			finish_xmote(gl, target);
			gfs2_glock_queue_work(gl, 0);
		    test_bit(DFL_UNMOUNT, &ls->ls_recover_flags)) {
			/*
			 * The lockspace has been released and the lock has
			 * been unlocked implicitly.
			 */
		} else if (ret) {
			fs_err(sdp, "lm_lock ret %d\n", ret);
			GLOCK_BUG_ON(gl, !gfs2_withdrawing_or_withdrawn(sdp));
			target = gl->gl_state | LM_OUT_ERROR;
		} else {
			/* The operation will be completed asynchronously. */
			return;
		}
	} else { /* lock_nolock */
	}

	/* Complete the operation now. */
	finish_xmote(gl, target);
	gfs2_glock_queue_work(gl, 0);
}
out:
	spin_lock(&gl->gl_lockref.lock);
}

/**
 * run_queue - do all outstanding tasks related to a glock
@@ -834,8 +872,9 @@ __acquires(&gl->gl_lockref.lock)
{
	struct gfs2_holder *gh = NULL;

	if (test_and_set_bit(GLF_LOCK, &gl->gl_flags))
	if (test_bit(GLF_LOCK, &gl->gl_flags))
		return;
	set_bit(GLF_LOCK, &gl->gl_flags);

	GLOCK_BUG_ON(gl, test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags));

@@ -865,7 +904,7 @@ __acquires(&gl->gl_lockref.lock)
	clear_bit(GLF_LOCK, &gl->gl_flags);
	smp_mb__after_atomic();
	gl->gl_lockref.count++;
	__gfs2_glock_queue_work(gl, 0);
	gfs2_glock_queue_work(gl, 0);
	return;

out_unlock:
@@ -1071,11 +1110,12 @@ static void glock_work_func(struct work_struct *work)
	struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_work.work);
	unsigned int drop_refs = 1;

	if (test_and_clear_bit(GLF_REPLY_PENDING, &gl->gl_flags)) {
	spin_lock(&gl->gl_lockref.lock);
	if (test_bit(GLF_REPLY_PENDING, &gl->gl_flags)) {
		clear_bit(GLF_REPLY_PENDING, &gl->gl_flags);
		finish_xmote(gl, gl->gl_reply);
		drop_refs++;
	}
	spin_lock(&gl->gl_lockref.lock);
	if (test_bit(GLF_PENDING_DEMOTE, &gl->gl_flags) &&
	    gl->gl_state != LM_ST_UNLOCKED &&
	    gl->gl_demote_state != LM_ST_EXCLUSIVE) {
@@ -1096,12 +1136,12 @@ static void glock_work_func(struct work_struct *work)
		drop_refs--;
		if (gl->gl_name.ln_type != LM_TYPE_INODE)
			delay = 0;
		__gfs2_glock_queue_work(gl, delay);
		gfs2_glock_queue_work(gl, delay);
	}

	/*
	 * Drop the remaining glock references manually here. (Mind that
	 * __gfs2_glock_queue_work depends on the lockref spinlock begin held
	 * gfs2_glock_queue_work depends on the lockref spinlock begin held
	 * here as well.)
	 */
	gl->gl_lockref.count -= drop_refs;
@@ -1606,7 +1646,7 @@ int gfs2_glock_nq(struct gfs2_holder *gh)
		     test_and_clear_bit(GLF_FROZEN, &gl->gl_flags))) {
		set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
		gl->gl_lockref.count++;
		__gfs2_glock_queue_work(gl, 0);
		gfs2_glock_queue_work(gl, 0);
	}
	run_queue(gl, 1);
	spin_unlock(&gl->gl_lockref.lock);
@@ -1672,7 +1712,7 @@ static void __gfs2_glock_dq(struct gfs2_holder *gh)
		    !test_bit(GLF_DEMOTE, &gl->gl_flags) &&
		    gl->gl_name.ln_type == LM_TYPE_INODE)
			delay = gl->gl_hold_time;
		__gfs2_glock_queue_work(gl, delay);
		gfs2_glock_queue_work(gl, delay);
	}
}

@@ -1896,7 +1936,7 @@ void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state)
			delay = gl->gl_hold_time;
	}
	handle_callback(gl, state, delay, true);
	__gfs2_glock_queue_work(gl, delay);
	gfs2_glock_queue_work(gl, delay);
	spin_unlock(&gl->gl_lockref.lock);
}

@@ -1956,7 +1996,7 @@ void gfs2_glock_complete(struct gfs2_glock *gl, int ret)

	gl->gl_lockref.count++;
	set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
	__gfs2_glock_queue_work(gl, 0);
	gfs2_glock_queue_work(gl, 0);
	spin_unlock(&gl->gl_lockref.lock);
}

@@ -1976,6 +2016,14 @@ static int glock_cmp(void *priv, const struct list_head *a,
	return 0;
}

static bool can_free_glock(struct gfs2_glock *gl)
{
	bool held = gl->gl_state != LM_ST_UNLOCKED;

	return !test_bit(GLF_LOCK, &gl->gl_flags) &&
	       gl->gl_lockref.count == held;
}

/**
 * gfs2_dispose_glock_lru - Demote a list of glocks
 * @list: The list to dispose of
@@ -1990,37 +2038,38 @@ static int glock_cmp(void *priv, const struct list_head *a,
 * private)
 */

static void gfs2_dispose_glock_lru(struct list_head *list)
static unsigned long gfs2_dispose_glock_lru(struct list_head *list)
__releases(&lru_lock)
__acquires(&lru_lock)
{
	struct gfs2_glock *gl;
	unsigned long freed = 0;

	list_sort(NULL, list, glock_cmp);

	while(!list_empty(list)) {
		gl = list_first_entry(list, struct gfs2_glock, gl_lru);
		list_del_init(&gl->gl_lru);
		clear_bit(GLF_LRU, &gl->gl_flags);
		if (!spin_trylock(&gl->gl_lockref.lock)) {
add_back_to_lru:
			list_add(&gl->gl_lru, &lru_list);
			set_bit(GLF_LRU, &gl->gl_flags);
			atomic_inc(&lru_count);
			list_move(&gl->gl_lru, &lru_list);
			continue;
		}
		if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
		if (!can_free_glock(gl)) {
			spin_unlock(&gl->gl_lockref.lock);
			goto add_back_to_lru;
		}
		list_del_init(&gl->gl_lru);
		atomic_dec(&lru_count);
		clear_bit(GLF_LRU, &gl->gl_flags);
		freed++;
		gl->gl_lockref.count++;
		if (demote_ok(gl))
			handle_callback(gl, LM_ST_UNLOCKED, 0, false);
		WARN_ON(!test_and_clear_bit(GLF_LOCK, &gl->gl_flags));
		__gfs2_glock_queue_work(gl, 0);
		gfs2_glock_queue_work(gl, 0);
		spin_unlock(&gl->gl_lockref.lock);
		cond_resched_lock(&lru_lock);
	}
	return freed;
}

/**
@@ -2032,32 +2081,21 @@ __acquires(&lru_lock)
 * gfs2_dispose_glock_lru() above.
 */

static long gfs2_scan_glock_lru(int nr)
static unsigned long gfs2_scan_glock_lru(unsigned long nr)
{
	struct gfs2_glock *gl, *next;
	LIST_HEAD(dispose);
	long freed = 0;
	unsigned long freed = 0;

	spin_lock(&lru_lock);
	list_for_each_entry_safe(gl, next, &lru_list, gl_lru) {
		if (nr-- <= 0)
		if (!nr--)
			break;
		/* Test for being demotable */
		if (!test_bit(GLF_LOCK, &gl->gl_flags)) {
			if (!spin_trylock(&gl->gl_lockref.lock))
				continue;
			if (gl->gl_lockref.count <= 1 &&
			    (gl->gl_state == LM_ST_UNLOCKED ||
			     demote_ok(gl))) {
		if (can_free_glock(gl))
			list_move(&gl->gl_lru, &dispose);
				atomic_dec(&lru_count);
				freed++;
			}
			spin_unlock(&gl->gl_lockref.lock);
		}
	}
	if (!list_empty(&dispose))
		gfs2_dispose_glock_lru(&dispose);
		freed = gfs2_dispose_glock_lru(&dispose);
	spin_unlock(&lru_lock);

	return freed;
@@ -2148,8 +2186,11 @@ static void thaw_glock(struct gfs2_glock *gl)
		return;
	if (!lockref_get_not_dead(&gl->gl_lockref))
		return;

	spin_lock(&gl->gl_lockref.lock);
	set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
	gfs2_glock_queue_work(gl, 0);
	spin_unlock(&gl->gl_lockref.lock);
}

/**
@@ -2167,7 +2208,7 @@ static void clear_glock(struct gfs2_glock *gl)
		gl->gl_lockref.count++;
		if (gl->gl_state != LM_ST_UNLOCKED)
			handle_callback(gl, LM_ST_UNLOCKED, 0, false);
		__gfs2_glock_queue_work(gl, 0);
		gfs2_glock_queue_work(gl, 0);
	}
	spin_unlock(&gl->gl_lockref.lock);
}
@@ -2225,6 +2266,8 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp)
	wait_event_timeout(sdp->sd_kill_wait,
			   atomic_read(&sdp->sd_glock_disposal) == 0,
			   HZ * 600);
	gfs2_lm_unmount(sdp);
	gfs2_free_dead_glocks(sdp);
	glock_hash_walk(dump_glock_func, sdp);
}

@@ -2529,8 +2572,7 @@ static void gfs2_glock_iter_next(struct gfs2_glock_iter *gi, loff_t n)
	if (gl) {
		if (n == 0)
			return;
		if (!lockref_put_not_zero(&gl->gl_lockref))
			gfs2_glock_queue_put(gl);
		gfs2_glock_put_async(gl);
	}
	for (;;) {
		gl = rhashtable_walk_next(&gi->hti);
+2 −1
Original line number Diff line number Diff line
@@ -172,7 +172,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
		   int create, struct gfs2_glock **glp);
struct gfs2_glock *gfs2_glock_hold(struct gfs2_glock *gl);
void gfs2_glock_put(struct gfs2_glock *gl);
void gfs2_glock_queue_put(struct gfs2_glock *gl);
void gfs2_glock_put_async(struct gfs2_glock *gl);

void __gfs2_holder_init(struct gfs2_glock *gl, unsigned int state,
		        u16 flags, struct gfs2_holder *gh,
@@ -252,6 +252,7 @@ void gfs2_gl_dq_holders(struct gfs2_sbd *sdp);
void gfs2_glock_thaw(struct gfs2_sbd *sdp);
void gfs2_glock_add_to_lru(struct gfs2_glock *gl);
void gfs2_glock_free(struct gfs2_glock *gl);
void gfs2_glock_free_later(struct gfs2_glock *gl);

int __init gfs2_glock_init(void);
void gfs2_glock_exit(void);
Loading