diff options
author | Bob Peterson <rpeterso@redhat.com> | 2016-06-09 15:24:07 -0400 |
---|---|---|
committer | Bob Peterson <rpeterso@redhat.com> | 2016-06-10 08:01:58 -0400 |
commit | 36e4ad0316c017d5b271378ed9a1c9a4b77fab5f (patch) | |
tree | 4a23a5f7ef511ce6b366c98cc0605bcb91985cb6 /fs/gfs2/rgrp.c | |
parent | 29567292c0b5b2fb484125c280a2175141fe2205 (diff) |
GFS2: don't set rgrp gl_object until it's inserted into rgrp tree
Before this patch, function read_rindex_entry would set a rgrp
glock's gl_object pointer to itself before inserting the rgrp into
the rgrp rbtree. The problem is: if another process was also reading
the rgrp in, and had already inserted its newly created rgrp, then
the second call to read_rindex_entry would overwrite that value,
then return a bad return code to the caller. Later, other functions
would reference the now-freed rgrp memory by way of gl_object.
In some cases, that could result in gfs2_rgrp_brelse being called
twice for the same rgrp: once for the failed attempt and once for
the "real" rgrp release. Eventually the kernel would panic.
There are also a number of other things that could go wrong when
a kernel module is accessing freed storage. For example, this could
result in rgrp corruption because the fake rgrp would point to a
fake bitmap in memory too, causing gfs2_inplace_reserve to search
some random memory for free blocks, and find some, since we were
never setting rgd->rd_bits to NULL before freeing it.
This patch fixes the problem by not setting gl_object until we
have successfully inserted the rgrp into the rbtree. Also, it sets
rd_bits to NULL as it frees them, which will ensure any accidental
access to the wrong rgrp will result in a kernel panic rather than
file system corruption, which is preferred.
Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Diffstat (limited to 'fs/gfs2/rgrp.c')
-rw-r--r-- | fs/gfs2/rgrp.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 5bd216901e89..960aaf43d665 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -722,6 +722,7 @@ void gfs2_clear_rgrpd(struct gfs2_sbd *sdp) | |||
722 | 722 | ||
723 | gfs2_free_clones(rgd); | 723 | gfs2_free_clones(rgd); |
724 | kfree(rgd->rd_bits); | 724 | kfree(rgd->rd_bits); |
725 | rgd->rd_bits = NULL; | ||
725 | return_all_reservations(rgd); | 726 | return_all_reservations(rgd); |
726 | kmem_cache_free(gfs2_rgrpd_cachep, rgd); | 727 | kmem_cache_free(gfs2_rgrpd_cachep, rgd); |
727 | } | 728 | } |
@@ -916,9 +917,6 @@ static int read_rindex_entry(struct gfs2_inode *ip) | |||
916 | if (error) | 917 | if (error) |
917 | goto fail; | 918 | goto fail; |
918 | 919 | ||
919 | rgd->rd_gl->gl_object = rgd; | ||
920 | rgd->rd_gl->gl_vm.start = (rgd->rd_addr * bsize) & PAGE_MASK; | ||
921 | rgd->rd_gl->gl_vm.end = PAGE_ALIGN((rgd->rd_addr + rgd->rd_length) * bsize) - 1; | ||
922 | rgd->rd_rgl = (struct gfs2_rgrp_lvb *)rgd->rd_gl->gl_lksb.sb_lvbptr; | 920 | rgd->rd_rgl = (struct gfs2_rgrp_lvb *)rgd->rd_gl->gl_lksb.sb_lvbptr; |
923 | rgd->rd_flags &= ~(GFS2_RDF_UPTODATE | GFS2_RDF_PREFERRED); | 921 | rgd->rd_flags &= ~(GFS2_RDF_UPTODATE | GFS2_RDF_PREFERRED); |
924 | if (rgd->rd_data > sdp->sd_max_rg_data) | 922 | if (rgd->rd_data > sdp->sd_max_rg_data) |
@@ -926,14 +924,20 @@ static int read_rindex_entry(struct gfs2_inode *ip) | |||
926 | spin_lock(&sdp->sd_rindex_spin); | 924 | spin_lock(&sdp->sd_rindex_spin); |
927 | error = rgd_insert(rgd); | 925 | error = rgd_insert(rgd); |
928 | spin_unlock(&sdp->sd_rindex_spin); | 926 | spin_unlock(&sdp->sd_rindex_spin); |
929 | if (!error) | 927 | if (!error) { |
928 | rgd->rd_gl->gl_object = rgd; | ||
929 | rgd->rd_gl->gl_vm.start = (rgd->rd_addr * bsize) & PAGE_MASK; | ||
930 | rgd->rd_gl->gl_vm.end = PAGE_ALIGN((rgd->rd_addr + | ||
931 | rgd->rd_length) * bsize) - 1; | ||
930 | return 0; | 932 | return 0; |
933 | } | ||
931 | 934 | ||
932 | error = 0; /* someone else read in the rgrp; free it and ignore it */ | 935 | error = 0; /* someone else read in the rgrp; free it and ignore it */ |
933 | gfs2_glock_put(rgd->rd_gl); | 936 | gfs2_glock_put(rgd->rd_gl); |
934 | 937 | ||
935 | fail: | 938 | fail: |
936 | kfree(rgd->rd_bits); | 939 | kfree(rgd->rd_bits); |
940 | rgd->rd_bits = NULL; | ||
937 | kmem_cache_free(gfs2_rgrpd_cachep, rgd); | 941 | kmem_cache_free(gfs2_rgrpd_cachep, rgd); |
938 | return error; | 942 | return error; |
939 | } | 943 | } |