diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/gfs2/aops.c | 13 | ||||
-rw-r--r-- | fs/gfs2/bmap.c | 2 | ||||
-rw-r--r-- | fs/gfs2/incore.h | 3 | ||||
-rw-r--r-- | fs/gfs2/log.c | 76 | ||||
-rw-r--r-- | fs/gfs2/log.h | 12 | ||||
-rw-r--r-- | fs/gfs2/ops_fstype.c | 1 | ||||
-rw-r--r-- | fs/gfs2/super.c | 1 | ||||
-rw-r--r-- | fs/gfs2/trans.c | 41 |
8 files changed, 79 insertions, 70 deletions
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 92340dd23bba..24f414f0ce61 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c | |||
@@ -230,16 +230,14 @@ out_ignore: | |||
230 | } | 230 | } |
231 | 231 | ||
232 | /** | 232 | /** |
233 | * gfs2_writeback_writepages - Write a bunch of dirty pages back to disk | 233 | * gfs2_writepages - Write a bunch of dirty pages back to disk |
234 | * @mapping: The mapping to write | 234 | * @mapping: The mapping to write |
235 | * @wbc: Write-back control | 235 | * @wbc: Write-back control |
236 | * | 236 | * |
237 | * For the data=writeback case we can already ignore buffer heads | 237 | * Used for both ordered and writeback modes. |
238 | * and write whole extents at once. This is a big reduction in the | ||
239 | * number of I/O requests we send and the bmap calls we make in this case. | ||
240 | */ | 238 | */ |
241 | static int gfs2_writeback_writepages(struct address_space *mapping, | 239 | static int gfs2_writepages(struct address_space *mapping, |
242 | struct writeback_control *wbc) | 240 | struct writeback_control *wbc) |
243 | { | 241 | { |
244 | return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc); | 242 | return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc); |
245 | } | 243 | } |
@@ -1102,7 +1100,7 @@ cannot_release: | |||
1102 | 1100 | ||
1103 | static const struct address_space_operations gfs2_writeback_aops = { | 1101 | static const struct address_space_operations gfs2_writeback_aops = { |
1104 | .writepage = gfs2_writeback_writepage, | 1102 | .writepage = gfs2_writeback_writepage, |
1105 | .writepages = gfs2_writeback_writepages, | 1103 | .writepages = gfs2_writepages, |
1106 | .readpage = gfs2_readpage, | 1104 | .readpage = gfs2_readpage, |
1107 | .readpages = gfs2_readpages, | 1105 | .readpages = gfs2_readpages, |
1108 | .write_begin = gfs2_write_begin, | 1106 | .write_begin = gfs2_write_begin, |
@@ -1118,6 +1116,7 @@ static const struct address_space_operations gfs2_writeback_aops = { | |||
1118 | 1116 | ||
1119 | static const struct address_space_operations gfs2_ordered_aops = { | 1117 | static const struct address_space_operations gfs2_ordered_aops = { |
1120 | .writepage = gfs2_ordered_writepage, | 1118 | .writepage = gfs2_ordered_writepage, |
1119 | .writepages = gfs2_writepages, | ||
1121 | .readpage = gfs2_readpage, | 1120 | .readpage = gfs2_readpage, |
1122 | .readpages = gfs2_readpages, | 1121 | .readpages = gfs2_readpages, |
1123 | .write_begin = gfs2_write_begin, | 1122 | .write_begin = gfs2_write_begin, |
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c index 7a8627569a25..d29d7793b211 100644 --- a/fs/gfs2/bmap.c +++ b/fs/gfs2/bmap.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "meta_io.h" | 22 | #include "meta_io.h" |
23 | #include "quota.h" | 23 | #include "quota.h" |
24 | #include "rgrp.h" | 24 | #include "rgrp.h" |
25 | #include "log.h" | ||
25 | #include "super.h" | 26 | #include "super.h" |
26 | #include "trans.h" | 27 | #include "trans.h" |
27 | #include "dir.h" | 28 | #include "dir.h" |
@@ -1137,6 +1138,7 @@ static int trunc_end(struct gfs2_inode *ip) | |||
1137 | ip->i_height = 0; | 1138 | ip->i_height = 0; |
1138 | ip->i_goal = ip->i_no_addr; | 1139 | ip->i_goal = ip->i_no_addr; |
1139 | gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); | 1140 | gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode)); |
1141 | gfs2_ordered_del_inode(ip); | ||
1140 | } | 1142 | } |
1141 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; | 1143 | ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME; |
1142 | ip->i_diskflags &= ~GFS2_DIF_TRUNC_IN_PROG; | 1144 | ip->i_diskflags &= ~GFS2_DIF_TRUNC_IN_PROG; |
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 19750bcb1ce7..1533cf8b4269 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h | |||
@@ -340,6 +340,7 @@ enum { | |||
340 | GIF_QD_LOCKED = 1, | 340 | GIF_QD_LOCKED = 1, |
341 | GIF_ALLOC_FAILED = 2, | 341 | GIF_ALLOC_FAILED = 2, |
342 | GIF_SW_PAGED = 3, | 342 | GIF_SW_PAGED = 3, |
343 | GIF_ORDERED = 4, | ||
343 | }; | 344 | }; |
344 | 345 | ||
345 | struct gfs2_inode { | 346 | struct gfs2_inode { |
@@ -356,6 +357,7 @@ struct gfs2_inode { | |||
356 | struct gfs2_rgrpd *i_rgd; | 357 | struct gfs2_rgrpd *i_rgd; |
357 | u64 i_goal; /* goal block for allocations */ | 358 | u64 i_goal; /* goal block for allocations */ |
358 | struct rw_semaphore i_rw_mutex; | 359 | struct rw_semaphore i_rw_mutex; |
360 | struct list_head i_ordered; | ||
359 | struct list_head i_trunc_list; | 361 | struct list_head i_trunc_list; |
360 | __be64 *i_hash_cache; | 362 | __be64 *i_hash_cache; |
361 | u32 i_entries; | 363 | u32 i_entries; |
@@ -722,6 +724,7 @@ struct gfs2_sbd { | |||
722 | struct list_head sd_log_le_revoke; | 724 | struct list_head sd_log_le_revoke; |
723 | struct list_head sd_log_le_databuf; | 725 | struct list_head sd_log_le_databuf; |
724 | struct list_head sd_log_le_ordered; | 726 | struct list_head sd_log_le_ordered; |
727 | spinlock_t sd_ordered_lock; | ||
725 | 728 | ||
726 | atomic_t sd_log_thresh1; | 729 | atomic_t sd_log_thresh1; |
727 | atomic_t sd_log_thresh2; | 730 | atomic_t sd_log_thresh2; |
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index f4beeb9c81c1..9a2ca8be7647 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c | |||
@@ -482,70 +482,66 @@ static void log_flush_wait(struct gfs2_sbd *sdp) | |||
482 | } | 482 | } |
483 | } | 483 | } |
484 | 484 | ||
485 | static int bd_cmp(void *priv, struct list_head *a, struct list_head *b) | 485 | static int ip_cmp(void *priv, struct list_head *a, struct list_head *b) |
486 | { | 486 | { |
487 | struct gfs2_bufdata *bda, *bdb; | 487 | struct gfs2_inode *ipa, *ipb; |
488 | 488 | ||
489 | bda = list_entry(a, struct gfs2_bufdata, bd_list); | 489 | ipa = list_entry(a, struct gfs2_inode, i_ordered); |
490 | bdb = list_entry(b, struct gfs2_bufdata, bd_list); | 490 | ipb = list_entry(b, struct gfs2_inode, i_ordered); |
491 | 491 | ||
492 | if (bda->bd_bh->b_blocknr < bdb->bd_bh->b_blocknr) | 492 | if (ipa->i_no_addr < ipb->i_no_addr) |
493 | return -1; | 493 | return -1; |
494 | if (bda->bd_bh->b_blocknr > bdb->bd_bh->b_blocknr) | 494 | if (ipa->i_no_addr > ipb->i_no_addr) |
495 | return 1; | 495 | return 1; |
496 | return 0; | 496 | return 0; |
497 | } | 497 | } |
498 | 498 | ||
499 | static void gfs2_ordered_write(struct gfs2_sbd *sdp) | 499 | static void gfs2_ordered_write(struct gfs2_sbd *sdp) |
500 | { | 500 | { |
501 | struct gfs2_bufdata *bd; | 501 | struct gfs2_inode *ip; |
502 | struct buffer_head *bh; | ||
503 | LIST_HEAD(written); | 502 | LIST_HEAD(written); |
504 | 503 | ||
505 | gfs2_log_lock(sdp); | 504 | spin_lock(&sdp->sd_ordered_lock); |
506 | list_sort(NULL, &sdp->sd_log_le_ordered, &bd_cmp); | 505 | list_sort(NULL, &sdp->sd_log_le_ordered, &ip_cmp); |
507 | while (!list_empty(&sdp->sd_log_le_ordered)) { | 506 | while (!list_empty(&sdp->sd_log_le_ordered)) { |
508 | bd = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_bufdata, bd_list); | 507 | ip = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_inode, i_ordered); |
509 | list_move(&bd->bd_list, &written); | 508 | list_move(&ip->i_ordered, &written); |
510 | bh = bd->bd_bh; | 509 | if (ip->i_inode.i_mapping->nrpages == 0) |
511 | if (!buffer_dirty(bh)) | ||
512 | continue; | 510 | continue; |
513 | get_bh(bh); | 511 | spin_unlock(&sdp->sd_ordered_lock); |
514 | gfs2_log_unlock(sdp); | 512 | filemap_fdatawrite(ip->i_inode.i_mapping); |
515 | lock_buffer(bh); | 513 | spin_lock(&sdp->sd_ordered_lock); |
516 | if (buffer_mapped(bh) && test_clear_buffer_dirty(bh)) { | ||
517 | bh->b_end_io = end_buffer_write_sync; | ||
518 | submit_bh(WRITE_SYNC, bh); | ||
519 | } else { | ||
520 | unlock_buffer(bh); | ||
521 | brelse(bh); | ||
522 | } | ||
523 | gfs2_log_lock(sdp); | ||
524 | } | 514 | } |
525 | list_splice(&written, &sdp->sd_log_le_ordered); | 515 | list_splice(&written, &sdp->sd_log_le_ordered); |
526 | gfs2_log_unlock(sdp); | 516 | spin_unlock(&sdp->sd_ordered_lock); |
527 | } | 517 | } |
528 | 518 | ||
529 | static void gfs2_ordered_wait(struct gfs2_sbd *sdp) | 519 | static void gfs2_ordered_wait(struct gfs2_sbd *sdp) |
530 | { | 520 | { |
531 | struct gfs2_bufdata *bd; | 521 | struct gfs2_inode *ip; |
532 | struct buffer_head *bh; | ||
533 | 522 | ||
534 | gfs2_log_lock(sdp); | 523 | spin_lock(&sdp->sd_ordered_lock); |
535 | while (!list_empty(&sdp->sd_log_le_ordered)) { | 524 | while (!list_empty(&sdp->sd_log_le_ordered)) { |
536 | bd = list_entry(sdp->sd_log_le_ordered.prev, struct gfs2_bufdata, bd_list); | 525 | ip = list_entry(sdp->sd_log_le_ordered.next, struct gfs2_inode, i_ordered); |
537 | bh = bd->bd_bh; | 526 | list_del(&ip->i_ordered); |
538 | if (buffer_locked(bh)) { | 527 | WARN_ON(!test_and_clear_bit(GIF_ORDERED, &ip->i_flags)); |
539 | get_bh(bh); | 528 | if (ip->i_inode.i_mapping->nrpages == 0) |
540 | gfs2_log_unlock(sdp); | ||
541 | wait_on_buffer(bh); | ||
542 | brelse(bh); | ||
543 | gfs2_log_lock(sdp); | ||
544 | continue; | 529 | continue; |
545 | } | 530 | spin_unlock(&sdp->sd_ordered_lock); |
546 | list_del_init(&bd->bd_list); | 531 | filemap_fdatawait(ip->i_inode.i_mapping); |
532 | spin_lock(&sdp->sd_ordered_lock); | ||
547 | } | 533 | } |
548 | gfs2_log_unlock(sdp); | 534 | spin_unlock(&sdp->sd_ordered_lock); |
535 | } | ||
536 | |||
537 | void gfs2_ordered_del_inode(struct gfs2_inode *ip) | ||
538 | { | ||
539 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | ||
540 | |||
541 | spin_lock(&sdp->sd_ordered_lock); | ||
542 | if (test_and_clear_bit(GIF_ORDERED, &ip->i_flags)) | ||
543 | list_del(&ip->i_ordered); | ||
544 | spin_unlock(&sdp->sd_ordered_lock); | ||
549 | } | 545 | } |
550 | 546 | ||
551 | /** | 547 | /** |
diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h index 3fd5215ea25f..3566f35915e0 100644 --- a/fs/gfs2/log.h +++ b/fs/gfs2/log.h | |||
@@ -48,6 +48,18 @@ static inline void gfs2_log_pointers_init(struct gfs2_sbd *sdp, | |||
48 | sdp->sd_log_head = sdp->sd_log_tail = value; | 48 | sdp->sd_log_head = sdp->sd_log_tail = value; |
49 | } | 49 | } |
50 | 50 | ||
51 | static inline void gfs2_ordered_add_inode(struct gfs2_inode *ip) | ||
52 | { | ||
53 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | ||
54 | |||
55 | if (!test_bit(GIF_ORDERED, &ip->i_flags)) { | ||
56 | spin_lock(&sdp->sd_ordered_lock); | ||
57 | if (!test_and_set_bit(GIF_ORDERED, &ip->i_flags)) | ||
58 | list_add(&ip->i_ordered, &sdp->sd_log_le_ordered); | ||
59 | spin_unlock(&sdp->sd_ordered_lock); | ||
60 | } | ||
61 | } | ||
62 | extern void gfs2_ordered_del_inode(struct gfs2_inode *ip); | ||
51 | extern unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, | 63 | extern unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct, |
52 | unsigned int ssize); | 64 | unsigned int ssize); |
53 | 65 | ||
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 5f5aba529fb1..e063f22d9e4c 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
@@ -102,6 +102,7 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb) | |||
102 | INIT_LIST_HEAD(&sdp->sd_log_le_revoke); | 102 | INIT_LIST_HEAD(&sdp->sd_log_le_revoke); |
103 | INIT_LIST_HEAD(&sdp->sd_log_le_databuf); | 103 | INIT_LIST_HEAD(&sdp->sd_log_le_databuf); |
104 | INIT_LIST_HEAD(&sdp->sd_log_le_ordered); | 104 | INIT_LIST_HEAD(&sdp->sd_log_le_ordered); |
105 | spin_lock_init(&sdp->sd_ordered_lock); | ||
105 | 106 | ||
106 | init_waitqueue_head(&sdp->sd_log_waitq); | 107 | init_waitqueue_head(&sdp->sd_log_waitq); |
107 | init_waitqueue_head(&sdp->sd_logd_waitq); | 108 | init_waitqueue_head(&sdp->sd_logd_waitq); |
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index c075b62aef59..a3b40eeaa6e2 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
@@ -1524,6 +1524,7 @@ out: | |||
1524 | /* Case 3 starts here */ | 1524 | /* Case 3 starts here */ |
1525 | truncate_inode_pages(&inode->i_data, 0); | 1525 | truncate_inode_pages(&inode->i_data, 0); |
1526 | gfs2_rs_delete(ip); | 1526 | gfs2_rs_delete(ip); |
1527 | gfs2_ordered_del_inode(ip); | ||
1527 | clear_inode(inode); | 1528 | clear_inode(inode); |
1528 | gfs2_dir_hash_inval(ip); | 1529 | gfs2_dir_hash_inval(ip); |
1529 | ip->i_gl->gl_object = NULL; | 1530 | ip->i_gl->gl_object = NULL; |
diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 14dbf6d3cdc0..88162fae27a5 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c | |||
@@ -159,7 +159,9 @@ static struct gfs2_bufdata *gfs2_alloc_bufdata(struct gfs2_glock *gl, | |||
159 | } | 159 | } |
160 | 160 | ||
161 | /** | 161 | /** |
162 | * databuf_lo_add - Add a databuf to the transaction. | 162 | * gfs2_trans_add_data - Add a databuf to the transaction. |
163 | * @gl: The inode glock associated with the buffer | ||
164 | * @bh: The buffer to add | ||
163 | * | 165 | * |
164 | * This is used in two distinct cases: | 166 | * This is used in two distinct cases: |
165 | * i) In ordered write mode | 167 | * i) In ordered write mode |
@@ -174,33 +176,18 @@ static struct gfs2_bufdata *gfs2_alloc_bufdata(struct gfs2_glock *gl, | |||
174 | * blocks, which isn't an enormous overhead but twice as much as | 176 | * blocks, which isn't an enormous overhead but twice as much as |
175 | * for normal metadata blocks. | 177 | * for normal metadata blocks. |
176 | */ | 178 | */ |
177 | static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) | 179 | void gfs2_trans_add_data(struct gfs2_glock *gl, struct buffer_head *bh) |
178 | { | 180 | { |
179 | struct gfs2_trans *tr = current->journal_info; | 181 | struct gfs2_trans *tr = current->journal_info; |
180 | struct address_space *mapping = bd->bd_bh->b_page->mapping; | 182 | struct gfs2_sbd *sdp = gl->gl_sbd; |
183 | struct address_space *mapping = bh->b_page->mapping; | ||
181 | struct gfs2_inode *ip = GFS2_I(mapping->host); | 184 | struct gfs2_inode *ip = GFS2_I(mapping->host); |
185 | struct gfs2_bufdata *bd; | ||
182 | 186 | ||
183 | if (tr) | 187 | if (!gfs2_is_jdata(ip)) { |
184 | tr->tr_touched = 1; | 188 | gfs2_ordered_add_inode(ip); |
185 | if (!list_empty(&bd->bd_list)) | ||
186 | return; | 189 | return; |
187 | set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags); | ||
188 | set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); | ||
189 | if (gfs2_is_jdata(ip)) { | ||
190 | gfs2_pin(sdp, bd->bd_bh); | ||
191 | tr->tr_num_databuf_new++; | ||
192 | sdp->sd_log_num_databuf++; | ||
193 | list_add_tail(&bd->bd_list, &sdp->sd_log_le_databuf); | ||
194 | } else { | ||
195 | list_add_tail(&bd->bd_list, &sdp->sd_log_le_ordered); | ||
196 | } | 190 | } |
197 | } | ||
198 | |||
199 | void gfs2_trans_add_data(struct gfs2_glock *gl, struct buffer_head *bh) | ||
200 | { | ||
201 | |||
202 | struct gfs2_sbd *sdp = gl->gl_sbd; | ||
203 | struct gfs2_bufdata *bd; | ||
204 | 191 | ||
205 | lock_buffer(bh); | 192 | lock_buffer(bh); |
206 | gfs2_log_lock(sdp); | 193 | gfs2_log_lock(sdp); |
@@ -214,7 +201,15 @@ void gfs2_trans_add_data(struct gfs2_glock *gl, struct buffer_head *bh) | |||
214 | gfs2_log_lock(sdp); | 201 | gfs2_log_lock(sdp); |
215 | } | 202 | } |
216 | gfs2_assert(sdp, bd->bd_gl == gl); | 203 | gfs2_assert(sdp, bd->bd_gl == gl); |
217 | databuf_lo_add(sdp, bd); | 204 | tr->tr_touched = 1; |
205 | if (list_empty(&bd->bd_list)) { | ||
206 | set_bit(GLF_LFLUSH, &bd->bd_gl->gl_flags); | ||
207 | set_bit(GLF_DIRTY, &bd->bd_gl->gl_flags); | ||
208 | gfs2_pin(sdp, bd->bd_bh); | ||
209 | tr->tr_num_databuf_new++; | ||
210 | sdp->sd_log_num_databuf++; | ||
211 | list_add_tail(&bd->bd_list, &sdp->sd_log_le_databuf); | ||
212 | } | ||
218 | gfs2_log_unlock(sdp); | 213 | gfs2_log_unlock(sdp); |
219 | unlock_buffer(bh); | 214 | unlock_buffer(bh); |
220 | } | 215 | } |