diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2006-08-04 23:41:22 +0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-08-04 23:41:22 +0400 |
commit | 59a1cc6bdabf5ed148b48808ad1a418d87f5e6bf (patch) | |
tree | 6463071a09201040267702e895d63359e62c393d /fs/gfs2/ops_vm.c | |
parent | 899bb264507cfed83922bf14cd66a073494601ba (diff) | |
download | linux-59a1cc6bdabf5ed148b48808ad1a418d87f5e6bf.tar.xz |
[GFS2] Fix lock ordering bug in page fault path
Mmapped files were able to trigger a lock ordering bug. Private
maps do not need to take the glock so early on. Shared maps do
unfortunately, however we can get around that by adding a flag
into the flags for the struct gfs2_file. This only works because
we are taking an exclusive lock at this point, so we know that
nobody else can be racing with us.
Fixes Red Hat bugzilla: #201196
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Diffstat (limited to 'fs/gfs2/ops_vm.c')
-rw-r--r-- | fs/gfs2/ops_vm.c | 20 |
1 files changed, 7 insertions, 13 deletions
diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c index aff66373b7e1..875a769444a1 100644 --- a/fs/gfs2/ops_vm.c +++ b/fs/gfs2/ops_vm.c @@ -46,13 +46,7 @@ static struct page *gfs2_private_nopage(struct vm_area_struct *area, unsigned long address, int *type) { struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host); - struct gfs2_holder i_gh; struct page *result; - int error; - - error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); - if (error) - return NULL; set_bit(GIF_PAGED, &ip->i_flags); @@ -61,8 +55,6 @@ static struct page *gfs2_private_nopage(struct vm_area_struct *area, if (result && result != NOPAGE_OOM) pfault_be_greedy(ip); - gfs2_glock_dq_uninit(&i_gh); - return result; } @@ -141,7 +133,9 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area, unsigned long address, int *type) { - struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host); + struct file *file = area->vm_file; + struct gfs2_file *gf = file->private_data; + struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); struct gfs2_holder i_gh; struct page *result = NULL; unsigned long index = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + @@ -156,13 +150,14 @@ static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area, set_bit(GIF_PAGED, &ip->i_flags); set_bit(GIF_SW_PAGED, &ip->i_flags); - error = gfs2_write_alloc_required(ip, - (uint64_t)index << PAGE_CACHE_SHIFT, + error = gfs2_write_alloc_required(ip, (u64)index << PAGE_CACHE_SHIFT, PAGE_CACHE_SIZE, &alloc_required); if (error) goto out; + set_bit(GFF_EXLOCK, &gf->f_flags); result = filemap_nopage(area, address, type); + clear_bit(GFF_EXLOCK, &gf->f_flags); if (!result || result == NOPAGE_OOM) goto out; @@ -177,8 +172,7 @@ static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area, } pfault_be_greedy(ip); - - out: +out: gfs2_glock_dq_uninit(&i_gh); return result; |