diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2006-08-04 15:41:22 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2006-08-04 15:41:22 -0400 |
commit | 59a1cc6bdabf5ed148b48808ad1a418d87f5e6bf (patch) | |
tree | 6463071a09201040267702e895d63359e62c393d /fs/gfs2/ops_vm.c | |
parent | 899bb264507cfed83922bf14cd66a073494601ba (diff) |
[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, | |||
46 | unsigned long address, int *type) | 46 | unsigned long address, int *type) |
47 | { | 47 | { |
48 | struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host); | 48 | struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host); |
49 | struct gfs2_holder i_gh; | ||
50 | struct page *result; | 49 | struct page *result; |
51 | int error; | ||
52 | |||
53 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); | ||
54 | if (error) | ||
55 | return NULL; | ||
56 | 50 | ||
57 | set_bit(GIF_PAGED, &ip->i_flags); | 51 | set_bit(GIF_PAGED, &ip->i_flags); |
58 | 52 | ||
@@ -61,8 +55,6 @@ static struct page *gfs2_private_nopage(struct vm_area_struct *area, | |||
61 | if (result && result != NOPAGE_OOM) | 55 | if (result && result != NOPAGE_OOM) |
62 | pfault_be_greedy(ip); | 56 | pfault_be_greedy(ip); |
63 | 57 | ||
64 | gfs2_glock_dq_uninit(&i_gh); | ||
65 | |||
66 | return result; | 58 | return result; |
67 | } | 59 | } |
68 | 60 | ||
@@ -141,7 +133,9 @@ static int alloc_page_backing(struct gfs2_inode *ip, struct page *page) | |||
141 | static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area, | 133 | static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area, |
142 | unsigned long address, int *type) | 134 | unsigned long address, int *type) |
143 | { | 135 | { |
144 | struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host); | 136 | struct file *file = area->vm_file; |
137 | struct gfs2_file *gf = file->private_data; | ||
138 | struct gfs2_inode *ip = GFS2_I(file->f_mapping->host); | ||
145 | struct gfs2_holder i_gh; | 139 | struct gfs2_holder i_gh; |
146 | struct page *result = NULL; | 140 | struct page *result = NULL; |
147 | unsigned long index = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) + | 141 | 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, | |||
156 | set_bit(GIF_PAGED, &ip->i_flags); | 150 | set_bit(GIF_PAGED, &ip->i_flags); |
157 | set_bit(GIF_SW_PAGED, &ip->i_flags); | 151 | set_bit(GIF_SW_PAGED, &ip->i_flags); |
158 | 152 | ||
159 | error = gfs2_write_alloc_required(ip, | 153 | error = gfs2_write_alloc_required(ip, (u64)index << PAGE_CACHE_SHIFT, |
160 | (uint64_t)index << PAGE_CACHE_SHIFT, | ||
161 | PAGE_CACHE_SIZE, &alloc_required); | 154 | PAGE_CACHE_SIZE, &alloc_required); |
162 | if (error) | 155 | if (error) |
163 | goto out; | 156 | goto out; |
164 | 157 | ||
158 | set_bit(GFF_EXLOCK, &gf->f_flags); | ||
165 | result = filemap_nopage(area, address, type); | 159 | result = filemap_nopage(area, address, type); |
160 | clear_bit(GFF_EXLOCK, &gf->f_flags); | ||
166 | if (!result || result == NOPAGE_OOM) | 161 | if (!result || result == NOPAGE_OOM) |
167 | goto out; | 162 | goto out; |
168 | 163 | ||
@@ -177,8 +172,7 @@ static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area, | |||
177 | } | 172 | } |
178 | 173 | ||
179 | pfault_be_greedy(ip); | 174 | pfault_be_greedy(ip); |
180 | 175 | out: | |
181 | out: | ||
182 | gfs2_glock_dq_uninit(&i_gh); | 176 | gfs2_glock_dq_uninit(&i_gh); |
183 | 177 | ||
184 | return result; | 178 | return result; |