diff options
author | Steven Whitehouse <swhiteho@redhat.com> | 2007-10-15 09:42:35 -0400 |
---|---|---|
committer | Steven Whitehouse <swhiteho@redhat.com> | 2008-01-25 03:07:11 -0500 |
commit | 51ff87bdd9f21a5d3672517b75d25ab5842d94a8 (patch) | |
tree | 7a8de5720b2a63e8d7d03a940a2b06196b2a3776 /fs | |
parent | cc7e79b168a552152299bd8a8254dc099aacc993 (diff) |
[GFS2] Clean up internal read function
As requested by Christoph, this patch cleans up GFS2's internal
read function so that it no longer uses the do_generic_mapping_read
function. This function is obsolete and GFS2 is the last user of it.
As a side effect the internal read code gets smaller and easier
to read and gfs2_readpage is split into two. One function has the locking
and the other function has the rest of the logic.
Signed-off-by: Steven Whitehouse <swhiteho@redhat.com>
Cc: Christoph Hellwig <hch@infradead.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/gfs2/inode.c | 1 | ||||
-rw-r--r-- | fs/gfs2/ops_address.c | 151 | ||||
-rw-r--r-- | fs/gfs2/ops_address.h | 3 | ||||
-rw-r--r-- | fs/gfs2/ops_file.c | 45 | ||||
-rw-r--r-- | fs/gfs2/ops_file.h | 24 | ||||
-rw-r--r-- | fs/gfs2/ops_inode.h | 4 | ||||
-rw-r--r-- | fs/gfs2/quota.c | 7 | ||||
-rw-r--r-- | fs/gfs2/rgrp.c | 2 |
8 files changed, 111 insertions, 126 deletions
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index 5f6dc32946cd..ad0fe373dca5 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
@@ -31,7 +31,6 @@ | |||
31 | #include "log.h" | 31 | #include "log.h" |
32 | #include "meta_io.h" | 32 | #include "meta_io.h" |
33 | #include "ops_address.h" | 33 | #include "ops_address.h" |
34 | #include "ops_file.h" | ||
35 | #include "ops_inode.h" | 34 | #include "ops_inode.h" |
36 | #include "quota.h" | 35 | #include "quota.h" |
37 | #include "rgrp.h" | 36 | #include "rgrp.h" |
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c index 9679f8b9870d..9bb24b1d9c05 100644 --- a/fs/gfs2/ops_address.c +++ b/fs/gfs2/ops_address.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/swap.h> | 20 | #include <linux/swap.h> |
21 | #include <linux/gfs2_ondisk.h> | 21 | #include <linux/gfs2_ondisk.h> |
22 | #include <linux/lm_interface.h> | 22 | #include <linux/lm_interface.h> |
23 | #include <linux/swap.h> | ||
23 | 24 | ||
24 | #include "gfs2.h" | 25 | #include "gfs2.h" |
25 | #include "incore.h" | 26 | #include "incore.h" |
@@ -32,7 +33,6 @@ | |||
32 | #include "quota.h" | 33 | #include "quota.h" |
33 | #include "trans.h" | 34 | #include "trans.h" |
34 | #include "rgrp.h" | 35 | #include "rgrp.h" |
35 | #include "ops_file.h" | ||
36 | #include "super.h" | 36 | #include "super.h" |
37 | #include "util.h" | 37 | #include "util.h" |
38 | #include "glops.h" | 38 | #include "glops.h" |
@@ -231,62 +231,115 @@ static int stuffed_readpage(struct gfs2_inode *ip, struct page *page) | |||
231 | 231 | ||
232 | 232 | ||
233 | /** | 233 | /** |
234 | * gfs2_readpage - readpage with locking | 234 | * __gfs2_readpage - readpage |
235 | * @file: The file to read a page for. N.B. This may be NULL if we are | 235 | * @file: The file to read a page for |
236 | * reading an internal file. | ||
237 | * @page: The page to read | 236 | * @page: The page to read |
238 | * | 237 | * |
239 | * Returns: errno | 238 | * This is the core of gfs2's readpage. Its used by the internal file |
239 | * reading code as in that case we already hold the glock. Also its | ||
240 | * called by gfs2_readpage() once the required lock has been granted. | ||
241 | * | ||
240 | */ | 242 | */ |
241 | 243 | ||
242 | static int gfs2_readpage(struct file *file, struct page *page) | 244 | static int __gfs2_readpage(void *file, struct page *page) |
243 | { | 245 | { |
244 | struct gfs2_inode *ip = GFS2_I(page->mapping->host); | 246 | struct gfs2_inode *ip = GFS2_I(page->mapping->host); |
245 | struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); | 247 | struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host); |
246 | struct gfs2_file *gf = NULL; | ||
247 | struct gfs2_holder gh; | ||
248 | int error; | 248 | int error; |
249 | int do_unlock = 0; | ||
250 | |||
251 | if (likely(file != &gfs2_internal_file_sentinel)) { | ||
252 | if (file) { | ||
253 | gf = file->private_data; | ||
254 | if (test_bit(GFF_EXLOCK, &gf->f_flags)) | ||
255 | /* gfs2_sharewrite_fault has grabbed the ip->i_gl already */ | ||
256 | goto skip_lock; | ||
257 | } | ||
258 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh); | ||
259 | do_unlock = 1; | ||
260 | error = gfs2_glock_nq_atime(&gh); | ||
261 | if (unlikely(error)) | ||
262 | goto out_unlock; | ||
263 | } | ||
264 | 249 | ||
265 | skip_lock: | ||
266 | if (gfs2_is_stuffed(ip)) { | 250 | if (gfs2_is_stuffed(ip)) { |
267 | error = stuffed_readpage(ip, page); | 251 | error = stuffed_readpage(ip, page); |
268 | unlock_page(page); | 252 | unlock_page(page); |
269 | } else | 253 | } else { |
270 | error = mpage_readpage(page, gfs2_get_block); | 254 | error = mpage_readpage(page, gfs2_get_block); |
255 | } | ||
271 | 256 | ||
272 | if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) | 257 | if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) |
273 | error = -EIO; | 258 | return -EIO; |
274 | 259 | ||
275 | if (do_unlock) { | 260 | return error; |
276 | gfs2_glock_dq_m(1, &gh); | 261 | } |
277 | gfs2_holder_uninit(&gh); | 262 | |
263 | /** | ||
264 | * gfs2_readpage - read a page of a file | ||
265 | * @file: The file to read | ||
266 | * @page: The page of the file | ||
267 | * | ||
268 | * This deals with the locking required. If the GFF_EXLOCK flags is set | ||
269 | * then we already hold the glock (due to page fault) and thus we call | ||
270 | * __gfs2_readpage() directly. Otherwise we use a trylock in order to | ||
271 | * avoid the page lock / glock ordering problems returning AOP_TRUNCATED_PAGE | ||
272 | * in the event that we are unable to get the lock. | ||
273 | */ | ||
274 | |||
275 | static int gfs2_readpage(struct file *file, struct page *page) | ||
276 | { | ||
277 | struct gfs2_inode *ip = GFS2_I(page->mapping->host); | ||
278 | struct gfs2_holder gh; | ||
279 | int error; | ||
280 | |||
281 | if (file) { | ||
282 | struct gfs2_file *gf = file->private_data; | ||
283 | if (test_bit(GFF_EXLOCK, &gf->f_flags)) | ||
284 | return __gfs2_readpage(file, page); | ||
278 | } | 285 | } |
286 | |||
287 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|LM_FLAG_TRY_1CB, &gh); | ||
288 | error = gfs2_glock_nq_atime(&gh); | ||
289 | if (unlikely(error)) { | ||
290 | unlock_page(page); | ||
291 | goto out; | ||
292 | } | ||
293 | error = __gfs2_readpage(file, page); | ||
294 | gfs2_glock_dq(&gh); | ||
279 | out: | 295 | out: |
280 | return error; | 296 | gfs2_holder_uninit(&gh); |
281 | out_unlock: | ||
282 | unlock_page(page); | ||
283 | if (error == GLR_TRYFAILED) { | 297 | if (error == GLR_TRYFAILED) { |
284 | error = AOP_TRUNCATED_PAGE; | ||
285 | yield(); | 298 | yield(); |
299 | return AOP_TRUNCATED_PAGE; | ||
286 | } | 300 | } |
287 | if (do_unlock) | 301 | return error; |
288 | gfs2_holder_uninit(&gh); | 302 | } |
289 | goto out; | 303 | |
304 | /** | ||
305 | * gfs2_internal_read - read an internal file | ||
306 | * @ip: The gfs2 inode | ||
307 | * @ra_state: The readahead state (or NULL for no readahead) | ||
308 | * @buf: The buffer to fill | ||
309 | * @pos: The file position | ||
310 | * @size: The amount to read | ||
311 | * | ||
312 | */ | ||
313 | |||
314 | int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, | ||
315 | char *buf, loff_t *pos, unsigned size) | ||
316 | { | ||
317 | struct address_space *mapping = ip->i_inode.i_mapping; | ||
318 | unsigned long index = *pos / PAGE_CACHE_SIZE; | ||
319 | unsigned offset = *pos & (PAGE_CACHE_SIZE - 1); | ||
320 | unsigned copied = 0; | ||
321 | unsigned amt; | ||
322 | struct page *page; | ||
323 | void *p; | ||
324 | |||
325 | do { | ||
326 | amt = size - copied; | ||
327 | if (offset + size > PAGE_CACHE_SIZE) | ||
328 | amt = PAGE_CACHE_SIZE - offset; | ||
329 | page = read_cache_page(mapping, index, __gfs2_readpage, NULL); | ||
330 | if (IS_ERR(page)) | ||
331 | return PTR_ERR(page); | ||
332 | p = kmap_atomic(page, KM_USER0); | ||
333 | memcpy(buf + copied, p + offset, amt); | ||
334 | kunmap_atomic(p, KM_USER0); | ||
335 | mark_page_accessed(page); | ||
336 | page_cache_release(page); | ||
337 | copied += amt; | ||
338 | index++; | ||
339 | offset = 0; | ||
340 | } while(copied < size); | ||
341 | (*pos) += size; | ||
342 | return size; | ||
290 | } | 343 | } |
291 | 344 | ||
292 | /** | 345 | /** |
@@ -314,21 +367,19 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping, | |||
314 | int ret = 0; | 367 | int ret = 0; |
315 | int do_unlock = 0; | 368 | int do_unlock = 0; |
316 | 369 | ||
317 | if (likely(file != &gfs2_internal_file_sentinel)) { | 370 | if (file) { |
318 | if (file) { | 371 | struct gfs2_file *gf = file->private_data; |
319 | struct gfs2_file *gf = file->private_data; | 372 | if (test_bit(GFF_EXLOCK, &gf->f_flags)) |
320 | if (test_bit(GFF_EXLOCK, &gf->f_flags)) | 373 | goto skip_lock; |
321 | goto skip_lock; | ||
322 | } | ||
323 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, | ||
324 | LM_FLAG_TRY_1CB|GL_ATIME, &gh); | ||
325 | do_unlock = 1; | ||
326 | ret = gfs2_glock_nq_atime(&gh); | ||
327 | if (ret == GLR_TRYFAILED) | ||
328 | goto out_noerror; | ||
329 | if (unlikely(ret)) | ||
330 | goto out_unlock; | ||
331 | } | 374 | } |
375 | gfs2_holder_init(ip->i_gl, LM_ST_SHARED, | ||
376 | LM_FLAG_TRY_1CB|GL_ATIME, &gh); | ||
377 | do_unlock = 1; | ||
378 | ret = gfs2_glock_nq_atime(&gh); | ||
379 | if (ret == GLR_TRYFAILED) | ||
380 | goto out_noerror; | ||
381 | if (unlikely(ret)) | ||
382 | goto out_unlock; | ||
332 | skip_lock: | 383 | skip_lock: |
333 | if (!gfs2_is_stuffed(ip)) | 384 | if (!gfs2_is_stuffed(ip)) |
334 | ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block); | 385 | ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block); |
diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h index fa1b5b3d28b9..e8fe83fcd583 100644 --- a/fs/gfs2/ops_address.h +++ b/fs/gfs2/ops_address.h | |||
@@ -18,5 +18,8 @@ extern const struct address_space_operations gfs2_file_aops; | |||
18 | extern int gfs2_get_block(struct inode *inode, sector_t lblock, | 18 | extern int gfs2_get_block(struct inode *inode, sector_t lblock, |
19 | struct buffer_head *bh_result, int create); | 19 | struct buffer_head *bh_result, int create); |
20 | extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask); | 20 | extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask); |
21 | extern int gfs2_internal_read(struct gfs2_inode *ip, | ||
22 | struct file_ra_state *ra_state, | ||
23 | char *buf, loff_t *pos, unsigned size); | ||
21 | 24 | ||
22 | #endif /* __OPS_ADDRESS_DOT_H__ */ | 25 | #endif /* __OPS_ADDRESS_DOT_H__ */ |
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c index bb11fd6752d3..a729c86b8be1 100644 --- a/fs/gfs2/ops_file.c +++ b/fs/gfs2/ops_file.c | |||
@@ -33,7 +33,6 @@ | |||
33 | #include "lm.h" | 33 | #include "lm.h" |
34 | #include "log.h" | 34 | #include "log.h" |
35 | #include "meta_io.h" | 35 | #include "meta_io.h" |
36 | #include "ops_file.h" | ||
37 | #include "ops_vm.h" | 36 | #include "ops_vm.h" |
38 | #include "quota.h" | 37 | #include "quota.h" |
39 | #include "rgrp.h" | 38 | #include "rgrp.h" |
@@ -41,50 +40,6 @@ | |||
41 | #include "util.h" | 40 | #include "util.h" |
42 | #include "eaops.h" | 41 | #include "eaops.h" |
43 | 42 | ||
44 | /* | ||
45 | * Most fields left uninitialised to catch anybody who tries to | ||
46 | * use them. f_flags set to prevent file_accessed() from touching | ||
47 | * any other part of this. Its use is purely as a flag so that we | ||
48 | * know (in readpage()) whether or not do to locking. | ||
49 | */ | ||
50 | struct file gfs2_internal_file_sentinel = { | ||
51 | .f_flags = O_NOATIME|O_RDONLY, | ||
52 | }; | ||
53 | |||
54 | static int gfs2_read_actor(read_descriptor_t *desc, struct page *page, | ||
55 | unsigned long offset, unsigned long size) | ||
56 | { | ||
57 | char *kaddr; | ||
58 | unsigned long count = desc->count; | ||
59 | |||
60 | if (size > count) | ||
61 | size = count; | ||
62 | |||
63 | kaddr = kmap(page); | ||
64 | memcpy(desc->arg.data, kaddr + offset, size); | ||
65 | kunmap(page); | ||
66 | |||
67 | desc->count = count - size; | ||
68 | desc->written += size; | ||
69 | desc->arg.buf += size; | ||
70 | return size; | ||
71 | } | ||
72 | |||
73 | int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state, | ||
74 | char *buf, loff_t *pos, unsigned size) | ||
75 | { | ||
76 | struct inode *inode = &ip->i_inode; | ||
77 | read_descriptor_t desc; | ||
78 | desc.written = 0; | ||
79 | desc.arg.data = buf; | ||
80 | desc.count = size; | ||
81 | desc.error = 0; | ||
82 | do_generic_mapping_read(inode->i_mapping, ra_state, | ||
83 | &gfs2_internal_file_sentinel, pos, &desc, | ||
84 | gfs2_read_actor); | ||
85 | return desc.written ? desc.written : desc.error; | ||
86 | } | ||
87 | |||
88 | /** | 43 | /** |
89 | * gfs2_llseek - seek to a location in a file | 44 | * gfs2_llseek - seek to a location in a file |
90 | * @file: the file | 45 | * @file: the file |
diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h deleted file mode 100644 index 7e5d8ec9c846..000000000000 --- a/fs/gfs2/ops_file.h +++ /dev/null | |||
@@ -1,24 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. | ||
3 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. | ||
4 | * | ||
5 | * This copyrighted material is made available to anyone wishing to use, | ||
6 | * modify, copy, or redistribute it subject to the terms and conditions | ||
7 | * of the GNU General Public License version 2. | ||
8 | */ | ||
9 | |||
10 | #ifndef __OPS_FILE_DOT_H__ | ||
11 | #define __OPS_FILE_DOT_H__ | ||
12 | |||
13 | #include <linux/fs.h> | ||
14 | struct gfs2_inode; | ||
15 | |||
16 | extern struct file gfs2_internal_file_sentinel; | ||
17 | extern int gfs2_internal_read(struct gfs2_inode *ip, | ||
18 | struct file_ra_state *ra_state, | ||
19 | char *buf, loff_t *pos, unsigned size); | ||
20 | extern void gfs2_set_inode_flags(struct inode *inode); | ||
21 | extern const struct file_operations gfs2_file_fops; | ||
22 | extern const struct file_operations gfs2_dir_fops; | ||
23 | |||
24 | #endif /* __OPS_FILE_DOT_H__ */ | ||
diff --git a/fs/gfs2/ops_inode.h b/fs/gfs2/ops_inode.h index 34f0caac1a03..edb519cb05ee 100644 --- a/fs/gfs2/ops_inode.h +++ b/fs/gfs2/ops_inode.h | |||
@@ -16,5 +16,9 @@ extern const struct inode_operations gfs2_file_iops; | |||
16 | extern const struct inode_operations gfs2_dir_iops; | 16 | extern const struct inode_operations gfs2_dir_iops; |
17 | extern const struct inode_operations gfs2_symlink_iops; | 17 | extern const struct inode_operations gfs2_symlink_iops; |
18 | extern const struct inode_operations gfs2_dev_iops; | 18 | extern const struct inode_operations gfs2_dev_iops; |
19 | extern const struct file_operations gfs2_file_fops; | ||
20 | extern const struct file_operations gfs2_dir_fops; | ||
21 | |||
22 | extern void gfs2_set_inode_flags(struct inode *inode); | ||
19 | 23 | ||
20 | #endif /* __OPS_INODE_DOT_H__ */ | 24 | #endif /* __OPS_INODE_DOT_H__ */ |
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index addb51e0f135..4996f0ef3007 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c | |||
@@ -59,7 +59,6 @@ | |||
59 | #include "super.h" | 59 | #include "super.h" |
60 | #include "trans.h" | 60 | #include "trans.h" |
61 | #include "inode.h" | 61 | #include "inode.h" |
62 | #include "ops_file.h" | ||
63 | #include "ops_address.h" | 62 | #include "ops_address.h" |
64 | #include "util.h" | 63 | #include "util.h" |
65 | 64 | ||
@@ -793,11 +792,9 @@ static int do_glock(struct gfs2_quota_data *qd, int force_refresh, | |||
793 | struct gfs2_holder i_gh; | 792 | struct gfs2_holder i_gh; |
794 | struct gfs2_quota_host q; | 793 | struct gfs2_quota_host q; |
795 | char buf[sizeof(struct gfs2_quota)]; | 794 | char buf[sizeof(struct gfs2_quota)]; |
796 | struct file_ra_state ra_state; | ||
797 | int error; | 795 | int error; |
798 | struct gfs2_quota_lvb *qlvb; | 796 | struct gfs2_quota_lvb *qlvb; |
799 | 797 | ||
800 | file_ra_state_init(&ra_state, sdp->sd_quota_inode->i_mapping); | ||
801 | restart: | 798 | restart: |
802 | error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh); | 799 | error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh); |
803 | if (error) | 800 | if (error) |
@@ -820,8 +817,8 @@ restart: | |||
820 | 817 | ||
821 | memset(buf, 0, sizeof(struct gfs2_quota)); | 818 | memset(buf, 0, sizeof(struct gfs2_quota)); |
822 | pos = qd2offset(qd); | 819 | pos = qd2offset(qd); |
823 | error = gfs2_internal_read(ip, &ra_state, buf, | 820 | error = gfs2_internal_read(ip, NULL, buf, &pos, |
824 | &pos, sizeof(struct gfs2_quota)); | 821 | sizeof(struct gfs2_quota)); |
825 | if (error < 0) | 822 | if (error < 0) |
826 | goto fail_gunlock; | 823 | goto fail_gunlock; |
827 | 824 | ||
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index 708c287e1d0e..09848aac45f6 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c | |||
@@ -25,10 +25,10 @@ | |||
25 | #include "rgrp.h" | 25 | #include "rgrp.h" |
26 | #include "super.h" | 26 | #include "super.h" |
27 | #include "trans.h" | 27 | #include "trans.h" |
28 | #include "ops_file.h" | ||
29 | #include "util.h" | 28 | #include "util.h" |
30 | #include "log.h" | 29 | #include "log.h" |
31 | #include "inode.h" | 30 | #include "inode.h" |
31 | #include "ops_address.h" | ||
32 | 32 | ||
33 | #define BFITNOENT ((u32)~0) | 33 | #define BFITNOENT ((u32)~0) |
34 | #define NO_BLOCK ((u64)~0) | 34 | #define NO_BLOCK ((u64)~0) |