aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fs-writeback.c
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2010-10-20 20:49:30 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2010-10-25 21:26:15 -0400
commit7ccf19a8042e343f8159f8a5fdd6a9422aa90c78 (patch)
tree9a69aaad6eb8992cae06f44dfea8c1d94f2a7f99 /fs/fs-writeback.c
parenta5491e0c7bb7387e3e6ff9994d6dc2efc78af56c (diff)
fs: inode split IO and LRU lists
The use of the same inode list structure (inode->i_list) for two different list constructs with different lifecycles and purposes makes it impossible to separate the locking of the different operations. Therefore, to enable the separation of the locking of the writeback and reclaim lists, split the inode->i_list into two separate lists dedicated to their specific tracking functions. Signed-off-by: Nick Piggin <npiggin@suse.de> Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/fs-writeback.c')
-rw-r--r--fs/fs-writeback.c35
1 files changed, 18 insertions, 17 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index e8f65290e836..7a24cc957f05 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -79,6 +79,11 @@ static inline struct backing_dev_info *inode_to_bdi(struct inode *inode)
79 return sb->s_bdi; 79 return sb->s_bdi;
80} 80}
81 81
82static inline struct inode *wb_inode(struct list_head *head)
83{
84 return list_entry(head, struct inode, i_wb_list);
85}
86
82static void bdi_queue_work(struct backing_dev_info *bdi, 87static void bdi_queue_work(struct backing_dev_info *bdi,
83 struct wb_writeback_work *work) 88 struct wb_writeback_work *work)
84{ 89{
@@ -172,11 +177,11 @@ static void redirty_tail(struct inode *inode)
172 if (!list_empty(&wb->b_dirty)) { 177 if (!list_empty(&wb->b_dirty)) {
173 struct inode *tail; 178 struct inode *tail;
174 179
175 tail = list_entry(wb->b_dirty.next, struct inode, i_list); 180 tail = wb_inode(wb->b_dirty.next);
176 if (time_before(inode->dirtied_when, tail->dirtied_when)) 181 if (time_before(inode->dirtied_when, tail->dirtied_when))
177 inode->dirtied_when = jiffies; 182 inode->dirtied_when = jiffies;
178 } 183 }
179 list_move(&inode->i_list, &wb->b_dirty); 184 list_move(&inode->i_wb_list, &wb->b_dirty);
180} 185}
181 186
182/* 187/*
@@ -186,7 +191,7 @@ static void requeue_io(struct inode *inode)
186{ 191{
187 struct bdi_writeback *wb = &inode_to_bdi(inode)->wb; 192 struct bdi_writeback *wb = &inode_to_bdi(inode)->wb;
188 193
189 list_move(&inode->i_list, &wb->b_more_io); 194 list_move(&inode->i_wb_list, &wb->b_more_io);
190} 195}
191 196
192static void inode_sync_complete(struct inode *inode) 197static void inode_sync_complete(struct inode *inode)
@@ -227,14 +232,14 @@ static void move_expired_inodes(struct list_head *delaying_queue,
227 int do_sb_sort = 0; 232 int do_sb_sort = 0;
228 233
229 while (!list_empty(delaying_queue)) { 234 while (!list_empty(delaying_queue)) {
230 inode = list_entry(delaying_queue->prev, struct inode, i_list); 235 inode = wb_inode(delaying_queue->prev);
231 if (older_than_this && 236 if (older_than_this &&
232 inode_dirtied_after(inode, *older_than_this)) 237 inode_dirtied_after(inode, *older_than_this))
233 break; 238 break;
234 if (sb && sb != inode->i_sb) 239 if (sb && sb != inode->i_sb)
235 do_sb_sort = 1; 240 do_sb_sort = 1;
236 sb = inode->i_sb; 241 sb = inode->i_sb;
237 list_move(&inode->i_list, &tmp); 242 list_move(&inode->i_wb_list, &tmp);
238 } 243 }
239 244
240 /* just one sb in list, splice to dispatch_queue and we're done */ 245 /* just one sb in list, splice to dispatch_queue and we're done */
@@ -245,12 +250,11 @@ static void move_expired_inodes(struct list_head *delaying_queue,
245 250
246 /* Move inodes from one superblock together */ 251 /* Move inodes from one superblock together */
247 while (!list_empty(&tmp)) { 252 while (!list_empty(&tmp)) {
248 inode = list_entry(tmp.prev, struct inode, i_list); 253 sb = wb_inode(tmp.prev)->i_sb;
249 sb = inode->i_sb;
250 list_for_each_prev_safe(pos, node, &tmp) { 254 list_for_each_prev_safe(pos, node, &tmp) {
251 inode = list_entry(pos, struct inode, i_list); 255 inode = wb_inode(pos);
252 if (inode->i_sb == sb) 256 if (inode->i_sb == sb)
253 list_move(&inode->i_list, dispatch_queue); 257 list_move(&inode->i_wb_list, dispatch_queue);
254 } 258 }
255 } 259 }
256} 260}
@@ -414,7 +418,7 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
414 * a reference to the inode or it's on it's way out. 418 * a reference to the inode or it's on it's way out.
415 * No need to add it back to the LRU. 419 * No need to add it back to the LRU.
416 */ 420 */
417 list_del_init(&inode->i_list); 421 list_del_init(&inode->i_wb_list);
418 } 422 }
419 } 423 }
420 inode_sync_complete(inode); 424 inode_sync_complete(inode);
@@ -462,8 +466,7 @@ static int writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb,
462{ 466{
463 while (!list_empty(&wb->b_io)) { 467 while (!list_empty(&wb->b_io)) {
464 long pages_skipped; 468 long pages_skipped;
465 struct inode *inode = list_entry(wb->b_io.prev, 469 struct inode *inode = wb_inode(wb->b_io.prev);
466 struct inode, i_list);
467 470
468 if (inode->i_sb != sb) { 471 if (inode->i_sb != sb) {
469 if (only_this_sb) { 472 if (only_this_sb) {
@@ -533,8 +536,7 @@ void writeback_inodes_wb(struct bdi_writeback *wb,
533 queue_io(wb, wbc->older_than_this); 536 queue_io(wb, wbc->older_than_this);
534 537
535 while (!list_empty(&wb->b_io)) { 538 while (!list_empty(&wb->b_io)) {
536 struct inode *inode = list_entry(wb->b_io.prev, 539 struct inode *inode = wb_inode(wb->b_io.prev);
537 struct inode, i_list);
538 struct super_block *sb = inode->i_sb; 540 struct super_block *sb = inode->i_sb;
539 541
540 if (!pin_sb_for_writeback(sb)) { 542 if (!pin_sb_for_writeback(sb)) {
@@ -672,8 +674,7 @@ static long wb_writeback(struct bdi_writeback *wb,
672 */ 674 */
673 spin_lock(&inode_lock); 675 spin_lock(&inode_lock);
674 if (!list_empty(&wb->b_more_io)) { 676 if (!list_empty(&wb->b_more_io)) {
675 inode = list_entry(wb->b_more_io.prev, 677 inode = wb_inode(wb->b_more_io.prev);
676 struct inode, i_list);
677 trace_wbc_writeback_wait(&wbc, wb->bdi); 678 trace_wbc_writeback_wait(&wbc, wb->bdi);
678 inode_wait_for_writeback(inode); 679 inode_wait_for_writeback(inode);
679 } 680 }
@@ -987,7 +988,7 @@ void __mark_inode_dirty(struct inode *inode, int flags)
987 } 988 }
988 989
989 inode->dirtied_when = jiffies; 990 inode->dirtied_when = jiffies;
990 list_move(&inode->i_list, &bdi->wb.b_dirty); 991 list_move(&inode->i_wb_list, &bdi->wb.b_dirty);
991 } 992 }
992 } 993 }
993out: 994out: