Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2ca99501 authored by Steven Whitehouse's avatar Steven Whitehouse
Browse files

[GFS2] Fix page lock/glock deadlock



This fixes a race between the glock and the page lock encountered
during truncate in gfs2_readpage and gfs2_prepare_write. The gfs2_readpages
function doesn't need the same fix since it only uses a try lock anyway, so
it will fail back to gfs2_readpage in the case of a potential deadlock.

This bug was spotted by Russell Cattelan.

Cc: Russell Cattelan <cattelan@redhat.com>
Signed-off-by: default avatarSteven Whitehouse <swhiteho@redhat.com>
parent c594d886
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -27,7 +27,6 @@
#define GL_ATIME		0x00000200
#define GL_NOCACHE		0x00000400
#define GL_NOCANCEL		0x00001000
#define GL_AOP			0x00004000

#define GLR_TRYFAILED		13
#define GLR_CANCELED		14
+9 −4
Original line number Diff line number Diff line
@@ -230,7 +230,7 @@ static int gfs2_readpage(struct file *file, struct page *page)
				/* gfs2_sharewrite_nopage has grabbed the ip->i_gl already */
				goto skip_lock;
		}
		gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|GL_AOP, &gh);
		gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh);
		do_unlock = 1;
		error = gfs2_glock_nq_m_atime(1, &gh);
		if (unlikely(error))
@@ -254,6 +254,8 @@ static int gfs2_readpage(struct file *file, struct page *page)
out:
	return error;
out_unlock:
	if (error == GLR_TRYFAILED)
		error = AOP_TRUNCATED_PAGE;
	unlock_page(page);
	if (do_unlock)
		gfs2_holder_uninit(&gh);
@@ -293,7 +295,7 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping,
				goto skip_lock;
		}
		gfs2_holder_init(ip->i_gl, LM_ST_SHARED,
				 LM_FLAG_TRY_1CB|GL_ATIME|GL_AOP, &gh);
				 LM_FLAG_TRY_1CB|GL_ATIME, &gh);
		do_unlock = 1;
		ret = gfs2_glock_nq_m_atime(1, &gh);
		if (ret == GLR_TRYFAILED)
@@ -366,10 +368,13 @@ static int gfs2_prepare_write(struct file *file, struct page *page,
	unsigned int write_len = to - from;


	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME|GL_AOP, &ip->i_gh);
	gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME|LM_FLAG_TRY_1CB, &ip->i_gh);
	error = gfs2_glock_nq_m_atime(1, &ip->i_gh);
	if (error)
	if (unlikely(error)) {
		if (error == GLR_TRYFAILED)
			error = AOP_TRUNCATED_PAGE;
		goto out_uninit;
	}

	gfs2_write_calc_reserv(ip, write_len, &data_blocks, &ind_blocks);