diff options
Diffstat (limited to 'patches/boot_time_opt/0112-fs-ext4-fsync-optimize-double-fsync-a-bunch.patch')
-rw-r--r-- | patches/boot_time_opt/0112-fs-ext4-fsync-optimize-double-fsync-a-bunch.patch | 158 |
1 files changed, 158 insertions, 0 deletions
diff --git a/patches/boot_time_opt/0112-fs-ext4-fsync-optimize-double-fsync-a-bunch.patch b/patches/boot_time_opt/0112-fs-ext4-fsync-optimize-double-fsync-a-bunch.patch new file mode 100644 index 0000000..7d0def8 --- /dev/null +++ b/patches/boot_time_opt/0112-fs-ext4-fsync-optimize-double-fsync-a-bunch.patch | |||
@@ -0,0 +1,158 @@ | |||
1 | From 3152053ea1ea3aa77bcc7e990d48ef84621ff6c9 Mon Sep 17 00:00:00 2001 | ||
2 | From: Arjan van de Ven <arjan@linux.intel.com> | ||
3 | Date: Sat, 9 Apr 2016 22:41:37 +0000 | ||
4 | Subject: [PATCH 112/124] fs: ext4: fsync: optimize double-fsync() a bunch | ||
5 | |||
6 | There are cases where EXT4 is a bit too conservative sending barriers down to the disk; | ||
7 | there are cases where the transaction in progress is not the one that sent the barrier | ||
8 | (in other words: the fsync is for a file for which the IO happened more time ago | ||
9 | and all data was already sent to the disk). For that case, a more performing tradeoff | ||
10 | can be made on SSD devices (which have the ability to flush their dram caches in a hurry | ||
11 | on a power fail event) where the barrier gets sent to the disk, but we don't need to wait | ||
12 | for the barrier to complete. Any consecutive IO will block on the barrier correctly. | ||
13 | --- | ||
14 | block/bio.c | 20 ++++++++++++++++++++ | ||
15 | block/blk-flush.c | 41 +++++++++++++++++++++++++++++++++++++++++ | ||
16 | fs/ext4/fsync.c | 6 +++++- | ||
17 | include/linux/bio.h | 1 + | ||
18 | include/linux/blkdev.h | 5 +++++ | ||
19 | 5 files changed, 72 insertions(+), 1 deletion(-) | ||
20 | |||
21 | diff --git a/block/bio.c b/block/bio.c | ||
22 | index db85c5753a76..80f5ab6b536a 100644 | ||
23 | --- a/block/bio.c | ||
24 | +++ b/block/bio.c | ||
25 | @@ -882,6 +882,26 @@ int submit_bio_wait(struct bio *bio) | ||
26 | } | ||
27 | EXPORT_SYMBOL(submit_bio_wait); | ||
28 | |||
29 | +static void submit_bio_nowait_endio(struct bio *bio) | ||
30 | +{ | ||
31 | + bio_put(bio); | ||
32 | +} | ||
33 | + | ||
34 | +/** | ||
35 | + * submit_bio_nowait - submit a bio for fire-and-forget | ||
36 | + * @rw: whether to %READ or %WRITE, or maybe to %READA (read ahead) | ||
37 | + * @bio: The &struct bio which describes the I/O | ||
38 | + * | ||
39 | + * Simple wrapper around submit_bio() that takes care of bio_put() on completion | ||
40 | + */ | ||
41 | +void submit_bio_nowait(struct bio *bio) | ||
42 | +{ | ||
43 | + bio->bi_end_io = submit_bio_nowait_endio; | ||
44 | + bio->bi_opf |= REQ_SYNC; | ||
45 | + submit_bio(bio); | ||
46 | +} | ||
47 | +EXPORT_SYMBOL(submit_bio_nowait); | ||
48 | + | ||
49 | /** | ||
50 | * bio_advance - increment/complete a bio by some number of bytes | ||
51 | * @bio: bio to advance | ||
52 | diff --git a/block/blk-flush.c b/block/blk-flush.c | ||
53 | index 3c882cbc7541..b2dfcfe01ed7 100644 | ||
54 | --- a/block/blk-flush.c | ||
55 | +++ b/block/blk-flush.c | ||
56 | @@ -530,6 +530,47 @@ int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask, | ||
57 | } | ||
58 | EXPORT_SYMBOL(blkdev_issue_flush); | ||
59 | |||
60 | +/** | ||
61 | + * blkdev_issue_flush_nowait - queue a flush | ||
62 | + * @bdev: blockdev to issue flush for | ||
63 | + * @gfp_mask: memory allocation flags (for bio_alloc) | ||
64 | + * @error_sector: error sector | ||
65 | + * | ||
66 | + * Description: | ||
67 | + * Issue a flush for the block device in question. Caller can supply | ||
68 | + * room for storing the error offset in case of a flush error, if they | ||
69 | + * wish to. If WAIT flag is not passed then caller may check only what | ||
70 | + * request was pushed in some internal queue for later handling. | ||
71 | + */ | ||
72 | +void blkdev_issue_flush_nowait(struct block_device *bdev, gfp_t gfp_mask) | ||
73 | +{ | ||
74 | + struct request_queue *q; | ||
75 | + struct bio *bio; | ||
76 | + | ||
77 | + if (bdev->bd_disk == NULL) | ||
78 | + return; | ||
79 | + | ||
80 | + q = bdev_get_queue(bdev); | ||
81 | + if (!q) | ||
82 | + return; | ||
83 | + | ||
84 | + /* | ||
85 | + * some block devices may not have their queue correctly set up here | ||
86 | + * (e.g. loop device without a backing file) and so issuing a flush | ||
87 | + * here will panic. Ensure there is a request function before issuing | ||
88 | + * the flush. | ||
89 | + */ | ||
90 | + if (!q->make_request_fn) | ||
91 | + return; | ||
92 | + | ||
93 | + bio = bio_alloc(gfp_mask, 0); | ||
94 | + bio->bi_bdev = bdev; | ||
95 | + bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_FLUSH); | ||
96 | + | ||
97 | + submit_bio_nowait(bio); | ||
98 | +} | ||
99 | +EXPORT_SYMBOL(blkdev_issue_flush_nowait); | ||
100 | + | ||
101 | struct blk_flush_queue *blk_alloc_flush_queue(struct request_queue *q, | ||
102 | int node, int cmd_size) | ||
103 | { | ||
104 | diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c | ||
105 | index 88effb1053c7..a58966c18172 100644 | ||
106 | --- a/fs/ext4/fsync.c | ||
107 | +++ b/fs/ext4/fsync.c | ||
108 | @@ -150,7 +150,11 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync) | ||
109 | ret = jbd2_complete_transaction(journal, commit_tid); | ||
110 | if (needs_barrier) { | ||
111 | issue_flush: | ||
112 | - err = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); | ||
113 | + err = 0; | ||
114 | + if (!blk_queue_nonrot(bdev_get_queue(inode->i_sb->s_bdev))) | ||
115 | + err = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); | ||
116 | + else | ||
117 | + blkdev_issue_flush_nowait(inode->i_sb->s_bdev, GFP_KERNEL); | ||
118 | if (!ret) | ||
119 | ret = err; | ||
120 | } | ||
121 | diff --git a/include/linux/bio.h b/include/linux/bio.h | ||
122 | index 97cb48f03dc7..3f055e6541e0 100644 | ||
123 | --- a/include/linux/bio.h | ||
124 | +++ b/include/linux/bio.h | ||
125 | @@ -421,6 +421,7 @@ struct request_queue; | ||
126 | extern int bio_phys_segments(struct request_queue *, struct bio *); | ||
127 | |||
128 | extern int submit_bio_wait(struct bio *bio); | ||
129 | +extern void submit_bio_nowait(struct bio *bio); | ||
130 | extern void bio_advance(struct bio *, unsigned); | ||
131 | |||
132 | extern void bio_init(struct bio *); | ||
133 | diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h | ||
134 | index f6a816129856..727684abf21e 100644 | ||
135 | --- a/include/linux/blkdev.h | ||
136 | +++ b/include/linux/blkdev.h | ||
137 | @@ -1144,6 +1144,7 @@ static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt, | ||
138 | #define BLKDEV_DISCARD_ZERO (1 << 1) /* must reliably zero data */ | ||
139 | |||
140 | extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *); | ||
141 | +extern void blkdev_issue_flush_nowait(struct block_device *, gfp_t); | ||
142 | extern int blkdev_issue_discard(struct block_device *bdev, sector_t sector, | ||
143 | sector_t nr_sects, gfp_t gfp_mask, unsigned long flags); | ||
144 | extern int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, | ||
145 | @@ -1745,6 +1746,10 @@ static inline int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask, | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | +static inline void blkdev_issue_flush_nowait(struct block_device *bdev, gfp_t gfp_mask) | ||
150 | +{ | ||
151 | +} | ||
152 | + | ||
153 | #endif /* CONFIG_BLOCK */ | ||
154 | |||
155 | #endif | ||
156 | -- | ||
157 | 2.11.1 | ||
158 | |||