diff options
Diffstat (limited to 'fs/fs-writeback.c')
-rw-r--r-- | fs/fs-writeback.c | 62 |
1 files changed, 51 insertions, 11 deletions
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 2d609a5fbfea..004686191354 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
@@ -247,14 +247,19 @@ static bool inode_dirtied_after(struct inode *inode, unsigned long t) | |||
247 | return ret; | 247 | return ret; |
248 | } | 248 | } |
249 | 249 | ||
250 | #define EXPIRE_DIRTY_ATIME 0x0001 | ||
251 | |||
250 | /* | 252 | /* |
251 | * Move expired (dirtied before work->older_than_this) dirty inodes from | 253 | * Move expired (dirtied before work->older_than_this) dirty inodes from |
252 | * @delaying_queue to @dispatch_queue. | 254 | * @delaying_queue to @dispatch_queue. |
253 | */ | 255 | */ |
254 | static int move_expired_inodes(struct list_head *delaying_queue, | 256 | static int move_expired_inodes(struct list_head *delaying_queue, |
255 | struct list_head *dispatch_queue, | 257 | struct list_head *dispatch_queue, |
258 | int flags, | ||
256 | struct wb_writeback_work *work) | 259 | struct wb_writeback_work *work) |
257 | { | 260 | { |
261 | unsigned long *older_than_this = NULL; | ||
262 | unsigned long expire_time; | ||
258 | LIST_HEAD(tmp); | 263 | LIST_HEAD(tmp); |
259 | struct list_head *pos, *node; | 264 | struct list_head *pos, *node; |
260 | struct super_block *sb = NULL; | 265 | struct super_block *sb = NULL; |
@@ -262,13 +267,21 @@ static int move_expired_inodes(struct list_head *delaying_queue, | |||
262 | int do_sb_sort = 0; | 267 | int do_sb_sort = 0; |
263 | int moved = 0; | 268 | int moved = 0; |
264 | 269 | ||
270 | if ((flags & EXPIRE_DIRTY_ATIME) == 0) | ||
271 | older_than_this = work->older_than_this; | ||
272 | else if ((work->reason == WB_REASON_SYNC) == 0) { | ||
273 | expire_time = jiffies - (HZ * 86400); | ||
274 | older_than_this = &expire_time; | ||
275 | } | ||
265 | while (!list_empty(delaying_queue)) { | 276 | while (!list_empty(delaying_queue)) { |
266 | inode = wb_inode(delaying_queue->prev); | 277 | inode = wb_inode(delaying_queue->prev); |
267 | if (work->older_than_this && | 278 | if (older_than_this && |
268 | inode_dirtied_after(inode, *work->older_than_this)) | 279 | inode_dirtied_after(inode, *older_than_this)) |
269 | break; | 280 | break; |
270 | list_move(&inode->i_wb_list, &tmp); | 281 | list_move(&inode->i_wb_list, &tmp); |
271 | moved++; | 282 | moved++; |
283 | if (flags & EXPIRE_DIRTY_ATIME) | ||
284 | set_bit(__I_DIRTY_TIME_EXPIRED, &inode->i_state); | ||
272 | if (sb_is_blkdev_sb(inode->i_sb)) | 285 | if (sb_is_blkdev_sb(inode->i_sb)) |
273 | continue; | 286 | continue; |
274 | if (sb && sb != inode->i_sb) | 287 | if (sb && sb != inode->i_sb) |
@@ -309,9 +322,12 @@ out: | |||
309 | static void queue_io(struct bdi_writeback *wb, struct wb_writeback_work *work) | 322 | static void queue_io(struct bdi_writeback *wb, struct wb_writeback_work *work) |
310 | { | 323 | { |
311 | int moved; | 324 | int moved; |
325 | |||
312 | assert_spin_locked(&wb->list_lock); | 326 | assert_spin_locked(&wb->list_lock); |
313 | list_splice_init(&wb->b_more_io, &wb->b_io); | 327 | list_splice_init(&wb->b_more_io, &wb->b_io); |
314 | moved = move_expired_inodes(&wb->b_dirty, &wb->b_io, work); | 328 | moved = move_expired_inodes(&wb->b_dirty, &wb->b_io, 0, work); |
329 | moved += move_expired_inodes(&wb->b_dirty_time, &wb->b_io, | ||
330 | EXPIRE_DIRTY_ATIME, work); | ||
315 | trace_writeback_queue_io(wb, work, moved); | 331 | trace_writeback_queue_io(wb, work, moved); |
316 | } | 332 | } |
317 | 333 | ||
@@ -435,6 +451,8 @@ static void requeue_inode(struct inode *inode, struct bdi_writeback *wb, | |||
435 | * updates after data IO completion. | 451 | * updates after data IO completion. |
436 | */ | 452 | */ |
437 | redirty_tail(inode, wb); | 453 | redirty_tail(inode, wb); |
454 | } else if (inode->i_state & I_DIRTY_TIME) { | ||
455 | list_move(&inode->i_wb_list, &wb->b_dirty_time); | ||
438 | } else { | 456 | } else { |
439 | /* The inode is clean. Remove from writeback lists. */ | 457 | /* The inode is clean. Remove from writeback lists. */ |
440 | list_del_init(&inode->i_wb_list); | 458 | list_del_init(&inode->i_wb_list); |
@@ -481,7 +499,13 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
481 | spin_lock(&inode->i_lock); | 499 | spin_lock(&inode->i_lock); |
482 | 500 | ||
483 | dirty = inode->i_state & I_DIRTY; | 501 | dirty = inode->i_state & I_DIRTY; |
484 | inode->i_state &= ~I_DIRTY; | 502 | if (((dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) && |
503 | (inode->i_state & I_DIRTY_TIME)) || | ||
504 | (inode->i_state & I_DIRTY_TIME_EXPIRED)) { | ||
505 | dirty |= I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED; | ||
506 | trace_writeback_lazytime(inode); | ||
507 | } | ||
508 | inode->i_state &= ~dirty; | ||
485 | 509 | ||
486 | /* | 510 | /* |
487 | * Paired with smp_mb() in __mark_inode_dirty(). This allows | 511 | * Paired with smp_mb() in __mark_inode_dirty(). This allows |
@@ -501,8 +525,10 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
501 | 525 | ||
502 | spin_unlock(&inode->i_lock); | 526 | spin_unlock(&inode->i_lock); |
503 | 527 | ||
528 | if (dirty & I_DIRTY_TIME) | ||
529 | mark_inode_dirty_sync(inode); | ||
504 | /* Don't write the inode if only I_DIRTY_PAGES was set */ | 530 | /* Don't write the inode if only I_DIRTY_PAGES was set */ |
505 | if (dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) { | 531 | if (dirty & ~I_DIRTY_PAGES) { |
506 | int err = write_inode(inode, wbc); | 532 | int err = write_inode(inode, wbc); |
507 | if (ret == 0) | 533 | if (ret == 0) |
508 | ret = err; | 534 | ret = err; |
@@ -550,7 +576,7 @@ writeback_single_inode(struct inode *inode, struct bdi_writeback *wb, | |||
550 | * make sure inode is on some writeback list and leave it there unless | 576 | * make sure inode is on some writeback list and leave it there unless |
551 | * we have completely cleaned the inode. | 577 | * we have completely cleaned the inode. |
552 | */ | 578 | */ |
553 | if (!(inode->i_state & I_DIRTY) && | 579 | if (!(inode->i_state & I_DIRTY_ALL) && |
554 | (wbc->sync_mode != WB_SYNC_ALL || | 580 | (wbc->sync_mode != WB_SYNC_ALL || |
555 | !mapping_tagged(inode->i_mapping, PAGECACHE_TAG_WRITEBACK))) | 581 | !mapping_tagged(inode->i_mapping, PAGECACHE_TAG_WRITEBACK))) |
556 | goto out; | 582 | goto out; |
@@ -565,7 +591,7 @@ writeback_single_inode(struct inode *inode, struct bdi_writeback *wb, | |||
565 | * If inode is clean, remove it from writeback lists. Otherwise don't | 591 | * If inode is clean, remove it from writeback lists. Otherwise don't |
566 | * touch it. See comment above for explanation. | 592 | * touch it. See comment above for explanation. |
567 | */ | 593 | */ |
568 | if (!(inode->i_state & I_DIRTY)) | 594 | if (!(inode->i_state & I_DIRTY_ALL)) |
569 | list_del_init(&inode->i_wb_list); | 595 | list_del_init(&inode->i_wb_list); |
570 | spin_unlock(&wb->list_lock); | 596 | spin_unlock(&wb->list_lock); |
571 | inode_sync_complete(inode); | 597 | inode_sync_complete(inode); |
@@ -707,7 +733,7 @@ static long writeback_sb_inodes(struct super_block *sb, | |||
707 | wrote += write_chunk - wbc.nr_to_write; | 733 | wrote += write_chunk - wbc.nr_to_write; |
708 | spin_lock(&wb->list_lock); | 734 | spin_lock(&wb->list_lock); |
709 | spin_lock(&inode->i_lock); | 735 | spin_lock(&inode->i_lock); |
710 | if (!(inode->i_state & I_DIRTY)) | 736 | if (!(inode->i_state & I_DIRTY_ALL)) |
711 | wrote++; | 737 | wrote++; |
712 | requeue_inode(inode, wb, &wbc); | 738 | requeue_inode(inode, wb, &wbc); |
713 | inode_sync_complete(inode); | 739 | inode_sync_complete(inode); |
@@ -1145,16 +1171,20 @@ static noinline void block_dump___mark_inode_dirty(struct inode *inode) | |||
1145 | * page->mapping->host, so the page-dirtying time is recorded in the internal | 1171 | * page->mapping->host, so the page-dirtying time is recorded in the internal |
1146 | * blockdev inode. | 1172 | * blockdev inode. |
1147 | */ | 1173 | */ |
1174 | #define I_DIRTY_INODE (I_DIRTY_SYNC | I_DIRTY_DATASYNC) | ||
1148 | void __mark_inode_dirty(struct inode *inode, int flags) | 1175 | void __mark_inode_dirty(struct inode *inode, int flags) |
1149 | { | 1176 | { |
1150 | struct super_block *sb = inode->i_sb; | 1177 | struct super_block *sb = inode->i_sb; |
1151 | struct backing_dev_info *bdi = NULL; | 1178 | struct backing_dev_info *bdi = NULL; |
1179 | int dirtytime; | ||
1180 | |||
1181 | trace_writeback_mark_inode_dirty(inode, flags); | ||
1152 | 1182 | ||
1153 | /* | 1183 | /* |
1154 | * Don't do this for I_DIRTY_PAGES - that doesn't actually | 1184 | * Don't do this for I_DIRTY_PAGES - that doesn't actually |
1155 | * dirty the inode itself | 1185 | * dirty the inode itself |
1156 | */ | 1186 | */ |
1157 | if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) { | 1187 | if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_TIME)) { |
1158 | trace_writeback_dirty_inode_start(inode, flags); | 1188 | trace_writeback_dirty_inode_start(inode, flags); |
1159 | 1189 | ||
1160 | if (sb->s_op->dirty_inode) | 1190 | if (sb->s_op->dirty_inode) |
@@ -1162,6 +1192,9 @@ void __mark_inode_dirty(struct inode *inode, int flags) | |||
1162 | 1192 | ||
1163 | trace_writeback_dirty_inode(inode, flags); | 1193 | trace_writeback_dirty_inode(inode, flags); |
1164 | } | 1194 | } |
1195 | if (flags & I_DIRTY_INODE) | ||
1196 | flags &= ~I_DIRTY_TIME; | ||
1197 | dirtytime = flags & I_DIRTY_TIME; | ||
1165 | 1198 | ||
1166 | /* | 1199 | /* |
1167 | * Paired with smp_mb() in __writeback_single_inode() for the | 1200 | * Paired with smp_mb() in __writeback_single_inode() for the |
@@ -1169,16 +1202,21 @@ void __mark_inode_dirty(struct inode *inode, int flags) | |||
1169 | */ | 1202 | */ |
1170 | smp_mb(); | 1203 | smp_mb(); |
1171 | 1204 | ||
1172 | if ((inode->i_state & flags) == flags) | 1205 | if (((inode->i_state & flags) == flags) || |
1206 | (dirtytime && (inode->i_state & I_DIRTY_INODE))) | ||
1173 | return; | 1207 | return; |
1174 | 1208 | ||
1175 | if (unlikely(block_dump)) | 1209 | if (unlikely(block_dump)) |
1176 | block_dump___mark_inode_dirty(inode); | 1210 | block_dump___mark_inode_dirty(inode); |
1177 | 1211 | ||
1178 | spin_lock(&inode->i_lock); | 1212 | spin_lock(&inode->i_lock); |
1213 | if (dirtytime && (inode->i_state & I_DIRTY_INODE)) | ||
1214 | goto out_unlock_inode; | ||
1179 | if ((inode->i_state & flags) != flags) { | 1215 | if ((inode->i_state & flags) != flags) { |
1180 | const int was_dirty = inode->i_state & I_DIRTY; | 1216 | const int was_dirty = inode->i_state & I_DIRTY; |
1181 | 1217 | ||
1218 | if (flags & I_DIRTY_INODE) | ||
1219 | inode->i_state &= ~I_DIRTY_TIME; | ||
1182 | inode->i_state |= flags; | 1220 | inode->i_state |= flags; |
1183 | 1221 | ||
1184 | /* | 1222 | /* |
@@ -1225,8 +1263,10 @@ void __mark_inode_dirty(struct inode *inode, int flags) | |||
1225 | } | 1263 | } |
1226 | 1264 | ||
1227 | inode->dirtied_when = jiffies; | 1265 | inode->dirtied_when = jiffies; |
1228 | list_move(&inode->i_wb_list, &bdi->wb.b_dirty); | 1266 | list_move(&inode->i_wb_list, dirtytime ? |
1267 | &bdi->wb.b_dirty_time : &bdi->wb.b_dirty); | ||
1229 | spin_unlock(&bdi->wb.list_lock); | 1268 | spin_unlock(&bdi->wb.list_lock); |
1269 | trace_writeback_dirty_inode_enqueue(inode); | ||
1230 | 1270 | ||
1231 | if (wakeup_bdi) | 1271 | if (wakeup_bdi) |
1232 | bdi_wakeup_thread_delayed(bdi); | 1272 | bdi_wakeup_thread_delayed(bdi); |