History

writeback: Generalize and expose wb_completion

wb_completion is used to track writeback completions. We want to use it from memcg side for foreign inode flushes. This patch updates it to remember the target waitq instead of assuming bdi->wb_waitq and expose it outside of fs-writeback.c.

Tejun Heo committed 7 years ago

Commit 5b9cce41 parent 38b4e093 files · +36 −33Browse files

Unified · Split

3 files
  1. fs/fs-writeback.c +14 −33
  2. include/linux/backing-dev-defs.h +20 −0
  3. include/linux/backing-dev.h +2 −0
fs/fs-writeback.c+14−33
@@ -36,10 +36,6 @@ · 35 unmodified lines
36 */36 */
37#define MIN_WRITEBACK_PAGES (4096UL >> (PAGE_SHIFT - 10))37#define MIN_WRITEBACK_PAGES (4096UL >> (PAGE_SHIFT - 10))
38 38
39struct wb_completion {
40 atomic_t cnt;
41};
42
43/*39/*
44 * Passed into wb_writeback(), essentially a subset of writeback_control40 * Passed into wb_writeback(), essentially a subset of writeback_control
45 */41 */
@@ -60,19 +56,6 @@ struct wb_writeback_work { · 14 unmodified lines
60 struct wb_completion *done; /* set if the caller waits */56 struct wb_completion *done; /* set if the caller waits */
61};57};
62 58
63/*
64 * If one wants to wait for one or more wb_writeback_works, each work's
65 * ->done should be set to a wb_completion defined using the following
66 * macro. Once all work items are issued with wb_queue_work(), the caller
67 * can wait for the completion of all using wb_wait_for_completion(). Work
68 * items which are waited upon aren't freed automatically on completion.
69 */
70#define DEFINE_WB_COMPLETION_ONSTACK(cmpl) \
71 struct wb_completion cmpl = { \
72 .cnt = ATOMIC_INIT(1), \
73 }
74
75
76/*59/*
77 * If an inode is constantly having its pages dirtied, but then the60 * If an inode is constantly having its pages dirtied, but then the
78 * updates stop dirtytime_expire_interval seconds in the past, it's61 * updates stop dirtytime_expire_interval seconds in the past, it's
@@ -182,7 +165,7 @@ static void finish_writeback_work(struct bdi_writeback *wb, · 103 unmodified lines
182 if (work->auto_free)165 if (work->auto_free)
183 kfree(work);166 kfree(work);
184 if (done && atomic_dec_and_test(&done->cnt))167 if (done && atomic_dec_and_test(&done->cnt))
185 wake_up_all(&wb->bdi->wb_waitq);168 wake_up_all(done->waitq);
186}169}
187 170
188static void wb_queue_work(struct bdi_writeback *wb,171static void wb_queue_work(struct bdi_writeback *wb,
@@ -206,20 +189,18 @@ static void wb_queue_work(struct bdi_writeback *wb, · 17 unmodified lines
206 189
207/**190/**
208 * wb_wait_for_completion - wait for completion of bdi_writeback_works191 * wb_wait_for_completion - wait for completion of bdi_writeback_works
209 * @bdi: bdi work items were issued to
210 * @done: target wb_completion192 * @done: target wb_completion
211 *193 *
212 * Wait for one or more work items issued to @bdi with their ->done field194 * Wait for one or more work items issued to @bdi with their ->done field
213 * set to @done, which should have been defined with195 * set to @done, which should have been initialized with
214 * DEFINE_WB_COMPLETION_ONSTACK(). This function returns after all such196 * DEFINE_WB_COMPLETION(). This function returns after all such work items
215 * work items are completed. Work items which are waited upon aren't freed197 * are completed. Work items which are waited upon aren't freed
216 * automatically on completion.198 * automatically on completion.
217 */199 */
218static void wb_wait_for_completion(struct backing_dev_info *bdi,200void wb_wait_for_completion(struct wb_completion *done)
219 struct wb_completion *done)
220{201{
221 atomic_dec(&done->cnt); /* put down the initial count */202 atomic_dec(&done->cnt); /* put down the initial count */
222 wait_event(bdi->wb_waitq, !atomic_read(&done->cnt));203 wait_event(*done->waitq, !atomic_read(&done->cnt));
223}204}
224 205
225#ifdef CONFIG_CGROUP_WRITEBACK206#ifdef CONFIG_CGROUP_WRITEBACK
@@ -854,7 +835,7 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi, · 628 unmodified lines
854restart:835restart:
855 rcu_read_lock();836 rcu_read_lock();
856 list_for_each_entry_continue_rcu(wb, &bdi->wb_list, bdi_node) {837 list_for_each_entry_continue_rcu(wb, &bdi->wb_list, bdi_node) {
857 DEFINE_WB_COMPLETION_ONSTACK(fallback_work_done);838 DEFINE_WB_COMPLETION(fallback_work_done, bdi);
858 struct wb_writeback_work fallback_work;839 struct wb_writeback_work fallback_work;
859 struct wb_writeback_work *work;840 struct wb_writeback_work *work;
860 long nr_pages;841 long nr_pages;
@@ -901,7 +882,7 @@ restart: · 40 unmodified lines
901 last_wb = wb;882 last_wb = wb;
902 883
903 rcu_read_unlock();884 rcu_read_unlock();
904 wb_wait_for_completion(bdi, &fallback_work_done);885 wb_wait_for_completion(&fallback_work_done);
905 goto restart;886 goto restart;
906 }887 }
907 rcu_read_unlock();888 rcu_read_unlock();
@@ -2373,7 +2354,8 @@ static void wait_sb_inodes(struct super_block *sb) · 1465 unmodified lines
2373static void __writeback_inodes_sb_nr(struct super_block *sb, unsigned long nr,2354static void __writeback_inodes_sb_nr(struct super_block *sb, unsigned long nr,
2374 enum wb_reason reason, bool skip_if_busy)2355 enum wb_reason reason, bool skip_if_busy)
2375{2356{
2376 DEFINE_WB_COMPLETION_ONSTACK(done);2357 struct backing_dev_info *bdi = sb->s_bdi;
2358 DEFINE_WB_COMPLETION(done, bdi);
2377 struct wb_writeback_work work = {2359 struct wb_writeback_work work = {
2378 .sb = sb,2360 .sb = sb,
2379 .sync_mode = WB_SYNC_NONE,2361 .sync_mode = WB_SYNC_NONE,
@@ -2382,14 +2364,13 @@ static void __writeback_inodes_sb_nr(struct super_block *sb, unsigned long nr, · 2 unmodified lines
2382 .nr_pages = nr,2364 .nr_pages = nr,
2383 .reason = reason,2365 .reason = reason,
2384 };2366 };
2385 struct backing_dev_info *bdi = sb->s_bdi;
2386 2367
2387 if (!bdi_has_dirty_io(bdi) || bdi == &noop_backing_dev_info)2368 if (!bdi_has_dirty_io(bdi) || bdi == &noop_backing_dev_info)
2388 return;2369 return;
2389 WARN_ON(!rwsem_is_locked(&sb->s_umount));2370 WARN_ON(!rwsem_is_locked(&sb->s_umount));
2390 2371
2391 bdi_split_work_to_wbs(sb->s_bdi, &work, skip_if_busy);2372 bdi_split_work_to_wbs(sb->s_bdi, &work, skip_if_busy);
2392 wb_wait_for_completion(bdi, &done);2373 wb_wait_for_completion(&done);
2393}2374}
2394 2375
2395/**2376/**
@@ -2451,7 +2432,8 @@ EXPORT_SYMBOL(try_to_writeback_inodes_sb); · 55 unmodified lines
2451 */2432 */
2452void sync_inodes_sb(struct super_block *sb)2433void sync_inodes_sb(struct super_block *sb)
2453{2434{
2454 DEFINE_WB_COMPLETION_ONSTACK(done);2435 struct backing_dev_info *bdi = sb->s_bdi;
2436 DEFINE_WB_COMPLETION(done, bdi);
2455 struct wb_writeback_work work = {2437 struct wb_writeback_work work = {
2456 .sb = sb,2438 .sb = sb,
2457 .sync_mode = WB_SYNC_ALL,2439 .sync_mode = WB_SYNC_ALL,
@@ -2461,7 +2443,6 @@ void sync_inodes_sb(struct super_block *sb) · 3 unmodified lines
2461 .reason = WB_REASON_SYNC,2443 .reason = WB_REASON_SYNC,
2462 .for_sync = 1,2444 .for_sync = 1,
2463 };2445 };
2464 struct backing_dev_info *bdi = sb->s_bdi;
2465 2446
2466 /*2447 /*
2467 * Can't skip on !bdi_has_dirty() because we should wait for !dirty2448 * Can't skip on !bdi_has_dirty() because we should wait for !dirty
@@ -2475,7 +2456,7 @@ void sync_inodes_sb(struct super_block *sb) · 7 unmodified lines
2475 /* protect against inode wb switch, see inode_switch_wbs_work_fn() */2456 /* protect against inode wb switch, see inode_switch_wbs_work_fn() */
2476 bdi_down_write_wb_switch_rwsem(bdi);2457 bdi_down_write_wb_switch_rwsem(bdi);
2477 bdi_split_work_to_wbs(bdi, &work, false);2458 bdi_split_work_to_wbs(bdi, &work, false);
2478 wb_wait_for_completion(bdi, &done);2459 wb_wait_for_completion(&done);
2479 bdi_up_write_wb_switch_rwsem(bdi);2460 bdi_up_write_wb_switch_rwsem(bdi);
2480 2461
2481 wait_sb_inodes(sb);2462 wait_sb_inodes(sb);
include/linux/backing-dev-defs.h+20−0
@@ -67,6 +67,26 @@ enum wb_reason { · 66 unmodified lines
67 WB_REASON_MAX,67 WB_REASON_MAX,
68};68};
69 69
70struct wb_completion {
71 atomic_t cnt;
72 wait_queue_head_t *waitq;
73};
74
75#define __WB_COMPLETION_INIT(_waitq) \
76 (struct wb_completion){ .cnt = ATOMIC_INIT(1), .waitq = (_waitq) }
77
78/*
79 * If one wants to wait for one or more wb_writeback_works, each work's
80 * ->done should be set to a wb_completion defined using the following
81 * macro. Once all work items are issued with wb_queue_work(), the caller
82 * can wait for the completion of all using wb_wait_for_completion(). Work
83 * items which are waited upon aren't freed automatically on completion.
84 */
85#define WB_COMPLETION_INIT(bdi) __WB_COMPLETION_INIT(&(bdi)->wb_waitq)
86
87#define DEFINE_WB_COMPLETION(cmpl, bdi) \
88 struct wb_completion cmpl = WB_COMPLETION_INIT(bdi)
89
70/*90/*
71 * For cgroup writeback, multiple wb's may map to the same blkcg. Those91 * For cgroup writeback, multiple wb's may map to the same blkcg. Those
72 * wb's can operate mostly independently but should share the congested92 * wb's can operate mostly independently but should share the congested
include/linux/backing-dev.h+2−0
@@ -44,6 +44,8 @@ void wb_start_background_writeback(struct bdi_writeback *wb); · 43 unmodified lines
44void wb_workfn(struct work_struct *work);44void wb_workfn(struct work_struct *work);
45void wb_wakeup_delayed(struct bdi_writeback *wb);45void wb_wakeup_delayed(struct bdi_writeback *wb);
46 46
47void wb_wait_for_completion(struct wb_completion *done);
48
47extern spinlock_t bdi_lock;49extern spinlock_t bdi_lock;
48extern struct list_head bdi_list;50extern struct list_head bdi_list;
49 51

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t