aboutsummaryrefslogtreecommitdiffstats
path: root/fs/gfs2
diff options
context:
space:
mode:
authorAbhijith Das <adas@redhat.com>2012-12-19 10:48:01 -0500
committerSteven Whitehouse <swhiteho@redhat.com>2013-01-02 05:04:53 -0500
commitf1213cacc7ffc7d4cdef3692f22b28a2df3216f5 (patch)
tree323a502b74dc45a726b05c5b0bddccb77ba516df /fs/gfs2
parentec1487528bed94c4aaff3687834fe94203880fd6 (diff)
GFS2: Fix race in gfs2_rs_alloc
QE aio tests uncovered a race condition in gfs2_rs_alloc where it's possible to come out of the function with a valid ip->i_res allocation but it gets freed before use resulting in a NULL ptr dereference. This patch envelopes the initial short-circuit check for non-NULL ip->i_res into the mutex lock. With this patch, I was able to successfully run the reproducer test multiple times. Resolves: rhbz#878476 Signed-off-by: Abhi Das <adas@redhat.com> Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2')
-rw-r--r--fs/gfs2/rgrp.c22
1 files changed, 10 insertions, 12 deletions
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 37ee061d899e..738b3888adc6 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -557,22 +557,20 @@ void gfs2_free_clones(struct gfs2_rgrpd *rgd)
557 */ 557 */
558int gfs2_rs_alloc(struct gfs2_inode *ip) 558int gfs2_rs_alloc(struct gfs2_inode *ip)
559{ 559{
560 struct gfs2_blkreserv *res; 560 int error = 0;
561 561
562 down_write(&ip->i_rw_mutex);
562 if (ip->i_res) 563 if (ip->i_res)
563 return 0; 564 goto out;
564
565 res = kmem_cache_zalloc(gfs2_rsrv_cachep, GFP_NOFS);
566 if (!res)
567 return -ENOMEM;
568 565
569 RB_CLEAR_NODE(&res->rs_node); 566 ip->i_res = kmem_cache_zalloc(gfs2_rsrv_cachep, GFP_NOFS);
567 if (!ip->i_res) {
568 error = -ENOMEM;
569 goto out;
570 }
570 571
571 down_write(&ip->i_rw_mutex); 572 RB_CLEAR_NODE(&ip->i_res->rs_node);
572 if (ip->i_res) 573out:
573 kmem_cache_free(gfs2_rsrv_cachep, res);
574 else
575 ip->i_res = res;
576 up_write(&ip->i_rw_mutex); 574 up_write(&ip->i_rw_mutex);
577 return 0; 575 return 0;
578} 576}