1ae98043fSRyusuke Konishi // SPDX-License-Identifier: GPL-2.0+
264b5a32eSRyusuke Konishi /*
394ee1d91SRyusuke Konishi * NILFS segment buffer
464b5a32eSRyusuke Konishi *
564b5a32eSRyusuke Konishi * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation.
664b5a32eSRyusuke Konishi *
74b420ab4SRyusuke Konishi * Written by Ryusuke Konishi.
864b5a32eSRyusuke Konishi *
964b5a32eSRyusuke Konishi */
1064b5a32eSRyusuke Konishi
1164b5a32eSRyusuke Konishi #include <linux/buffer_head.h>
1264b5a32eSRyusuke Konishi #include <linux/writeback.h>
1364b5a32eSRyusuke Konishi #include <linux/crc32.h>
149c965bacSRyusuke Konishi #include <linux/backing-dev.h>
155a0e3ad6STejun Heo #include <linux/slab.h>
1664b5a32eSRyusuke Konishi #include "page.h"
1764b5a32eSRyusuke Konishi #include "segbuf.h"
1864b5a32eSRyusuke Konishi
1964b5a32eSRyusuke Konishi
209c965bacSRyusuke Konishi struct nilfs_write_info {
219c965bacSRyusuke Konishi struct the_nilfs *nilfs;
229c965bacSRyusuke Konishi struct bio *bio;
239c965bacSRyusuke Konishi int start, end; /* The region to be submitted */
249c965bacSRyusuke Konishi int rest_blocks;
259c965bacSRyusuke Konishi int max_pages;
269c965bacSRyusuke Konishi int nr_vecs;
279c965bacSRyusuke Konishi sector_t blocknr;
289c965bacSRyusuke Konishi };
299c965bacSRyusuke Konishi
30d1c6b72aSRyusuke Konishi static int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf,
31d1c6b72aSRyusuke Konishi struct the_nilfs *nilfs);
32d1c6b72aSRyusuke Konishi static int nilfs_segbuf_wait(struct nilfs_segment_buffer *segbuf);
33d1c6b72aSRyusuke Konishi
nilfs_segbuf_new(struct super_block * sb)3464b5a32eSRyusuke Konishi struct nilfs_segment_buffer *nilfs_segbuf_new(struct super_block *sb)
3564b5a32eSRyusuke Konishi {
3664b5a32eSRyusuke Konishi struct nilfs_segment_buffer *segbuf;
3764b5a32eSRyusuke Konishi
3864b5a32eSRyusuke Konishi segbuf = kmem_cache_alloc(nilfs_segbuf_cachep, GFP_NOFS);
3964b5a32eSRyusuke Konishi if (unlikely(!segbuf))
4064b5a32eSRyusuke Konishi return NULL;
4164b5a32eSRyusuke Konishi
4264b5a32eSRyusuke Konishi segbuf->sb_super = sb;
4364b5a32eSRyusuke Konishi INIT_LIST_HEAD(&segbuf->sb_list);
4464b5a32eSRyusuke Konishi INIT_LIST_HEAD(&segbuf->sb_segsum_buffers);
4564b5a32eSRyusuke Konishi INIT_LIST_HEAD(&segbuf->sb_payload_buffers);
461e2b68bfSRyusuke Konishi segbuf->sb_super_root = NULL;
479284ad2aSRyusuke Konishi
489284ad2aSRyusuke Konishi init_completion(&segbuf->sb_bio_event);
499284ad2aSRyusuke Konishi atomic_set(&segbuf->sb_err, 0);
509284ad2aSRyusuke Konishi segbuf->sb_nbio = 0;
519284ad2aSRyusuke Konishi
5264b5a32eSRyusuke Konishi return segbuf;
5364b5a32eSRyusuke Konishi }
5464b5a32eSRyusuke Konishi
nilfs_segbuf_free(struct nilfs_segment_buffer * segbuf)5564b5a32eSRyusuke Konishi void nilfs_segbuf_free(struct nilfs_segment_buffer *segbuf)
5664b5a32eSRyusuke Konishi {
5764b5a32eSRyusuke Konishi kmem_cache_free(nilfs_segbuf_cachep, segbuf);
5864b5a32eSRyusuke Konishi }
5964b5a32eSRyusuke Konishi
nilfs_segbuf_map(struct nilfs_segment_buffer * segbuf,__u64 segnum,unsigned long offset,struct the_nilfs * nilfs)60cece5520SRyusuke Konishi void nilfs_segbuf_map(struct nilfs_segment_buffer *segbuf, __u64 segnum,
6164b5a32eSRyusuke Konishi unsigned long offset, struct the_nilfs *nilfs)
6264b5a32eSRyusuke Konishi {
6364b5a32eSRyusuke Konishi segbuf->sb_segnum = segnum;
6464b5a32eSRyusuke Konishi nilfs_get_segment_range(nilfs, segnum, &segbuf->sb_fseg_start,
6564b5a32eSRyusuke Konishi &segbuf->sb_fseg_end);
6664b5a32eSRyusuke Konishi
6764b5a32eSRyusuke Konishi segbuf->sb_pseg_start = segbuf->sb_fseg_start + offset;
6864b5a32eSRyusuke Konishi segbuf->sb_rest_blocks =
6964b5a32eSRyusuke Konishi segbuf->sb_fseg_end - segbuf->sb_pseg_start + 1;
7064b5a32eSRyusuke Konishi }
7164b5a32eSRyusuke Konishi
72a694291aSRyusuke Konishi /**
73a694291aSRyusuke Konishi * nilfs_segbuf_map_cont - map a new log behind a given log
74a694291aSRyusuke Konishi * @segbuf: new segment buffer
75a694291aSRyusuke Konishi * @prev: segment buffer containing a log to be continued
76a694291aSRyusuke Konishi */
nilfs_segbuf_map_cont(struct nilfs_segment_buffer * segbuf,struct nilfs_segment_buffer * prev)77a694291aSRyusuke Konishi void nilfs_segbuf_map_cont(struct nilfs_segment_buffer *segbuf,
78a694291aSRyusuke Konishi struct nilfs_segment_buffer *prev)
79a694291aSRyusuke Konishi {
80a694291aSRyusuke Konishi segbuf->sb_segnum = prev->sb_segnum;
81a694291aSRyusuke Konishi segbuf->sb_fseg_start = prev->sb_fseg_start;
82a694291aSRyusuke Konishi segbuf->sb_fseg_end = prev->sb_fseg_end;
83a694291aSRyusuke Konishi segbuf->sb_pseg_start = prev->sb_pseg_start + prev->sb_sum.nblocks;
84a694291aSRyusuke Konishi segbuf->sb_rest_blocks =
85a694291aSRyusuke Konishi segbuf->sb_fseg_end - segbuf->sb_pseg_start + 1;
86a694291aSRyusuke Konishi }
87a694291aSRyusuke Konishi
nilfs_segbuf_set_next_segnum(struct nilfs_segment_buffer * segbuf,__u64 nextnum,struct the_nilfs * nilfs)8864b5a32eSRyusuke Konishi void nilfs_segbuf_set_next_segnum(struct nilfs_segment_buffer *segbuf,
8964b5a32eSRyusuke Konishi __u64 nextnum, struct the_nilfs *nilfs)
9064b5a32eSRyusuke Konishi {
9164b5a32eSRyusuke Konishi segbuf->sb_nextnum = nextnum;
9264b5a32eSRyusuke Konishi segbuf->sb_sum.next = nilfs_get_segment_start_blocknr(nilfs, nextnum);
9364b5a32eSRyusuke Konishi }
9464b5a32eSRyusuke Konishi
nilfs_segbuf_extend_segsum(struct nilfs_segment_buffer * segbuf)9564b5a32eSRyusuke Konishi int nilfs_segbuf_extend_segsum(struct nilfs_segment_buffer *segbuf)
9664b5a32eSRyusuke Konishi {
9764b5a32eSRyusuke Konishi struct buffer_head *bh;
9864b5a32eSRyusuke Konishi
9964b5a32eSRyusuke Konishi bh = sb_getblk(segbuf->sb_super,
10064b5a32eSRyusuke Konishi segbuf->sb_pseg_start + segbuf->sb_sum.nsumblk);
10164b5a32eSRyusuke Konishi if (unlikely(!bh))
10264b5a32eSRyusuke Konishi return -ENOMEM;
10364b5a32eSRyusuke Konishi
104*679bd7ebSRyusuke Konishi lock_buffer(bh);
105*679bd7ebSRyusuke Konishi if (!buffer_uptodate(bh)) {
106*679bd7ebSRyusuke Konishi memset(bh->b_data, 0, bh->b_size);
107*679bd7ebSRyusuke Konishi set_buffer_uptodate(bh);
108*679bd7ebSRyusuke Konishi }
109*679bd7ebSRyusuke Konishi unlock_buffer(bh);
11064b5a32eSRyusuke Konishi nilfs_segbuf_add_segsum_buffer(segbuf, bh);
11164b5a32eSRyusuke Konishi return 0;
11264b5a32eSRyusuke Konishi }
11364b5a32eSRyusuke Konishi
nilfs_segbuf_extend_payload(struct nilfs_segment_buffer * segbuf,struct buffer_head ** bhp)11464b5a32eSRyusuke Konishi int nilfs_segbuf_extend_payload(struct nilfs_segment_buffer *segbuf,
11564b5a32eSRyusuke Konishi struct buffer_head **bhp)
11664b5a32eSRyusuke Konishi {
11764b5a32eSRyusuke Konishi struct buffer_head *bh;
11864b5a32eSRyusuke Konishi
11964b5a32eSRyusuke Konishi bh = sb_getblk(segbuf->sb_super,
12064b5a32eSRyusuke Konishi segbuf->sb_pseg_start + segbuf->sb_sum.nblocks);
12164b5a32eSRyusuke Konishi if (unlikely(!bh))
12264b5a32eSRyusuke Konishi return -ENOMEM;
12364b5a32eSRyusuke Konishi
12464b5a32eSRyusuke Konishi nilfs_segbuf_add_payload_buffer(segbuf, bh);
12564b5a32eSRyusuke Konishi *bhp = bh;
12664b5a32eSRyusuke Konishi return 0;
12764b5a32eSRyusuke Konishi }
12864b5a32eSRyusuke Konishi
nilfs_segbuf_reset(struct nilfs_segment_buffer * segbuf,unsigned int flags,time64_t ctime,__u64 cno)1290c6c44cbSRyusuke Konishi int nilfs_segbuf_reset(struct nilfs_segment_buffer *segbuf, unsigned int flags,
130fb04b91bSArnd Bergmann time64_t ctime, __u64 cno)
13164b5a32eSRyusuke Konishi {
13264b5a32eSRyusuke Konishi int err;
13364b5a32eSRyusuke Konishi
13464b5a32eSRyusuke Konishi segbuf->sb_sum.nblocks = segbuf->sb_sum.nsumblk = 0;
13564b5a32eSRyusuke Konishi err = nilfs_segbuf_extend_segsum(segbuf);
13664b5a32eSRyusuke Konishi if (unlikely(err))
13764b5a32eSRyusuke Konishi return err;
13864b5a32eSRyusuke Konishi
13964b5a32eSRyusuke Konishi segbuf->sb_sum.flags = flags;
14064b5a32eSRyusuke Konishi segbuf->sb_sum.sumbytes = sizeof(struct nilfs_segment_summary);
14164b5a32eSRyusuke Konishi segbuf->sb_sum.nfinfo = segbuf->sb_sum.nfileblk = 0;
14264b5a32eSRyusuke Konishi segbuf->sb_sum.ctime = ctime;
14350614bcfSRyusuke Konishi segbuf->sb_sum.cno = cno;
14464b5a32eSRyusuke Konishi return 0;
14564b5a32eSRyusuke Konishi }
14664b5a32eSRyusuke Konishi
14764b5a32eSRyusuke Konishi /*
1487a65004bSRyusuke Konishi * Setup segment summary
14964b5a32eSRyusuke Konishi */
nilfs_segbuf_fill_in_segsum(struct nilfs_segment_buffer * segbuf)15064b5a32eSRyusuke Konishi void nilfs_segbuf_fill_in_segsum(struct nilfs_segment_buffer *segbuf)
15164b5a32eSRyusuke Konishi {
15264b5a32eSRyusuke Konishi struct nilfs_segment_summary *raw_sum;
15364b5a32eSRyusuke Konishi struct buffer_head *bh_sum;
15464b5a32eSRyusuke Konishi
15564b5a32eSRyusuke Konishi bh_sum = list_entry(segbuf->sb_segsum_buffers.next,
15664b5a32eSRyusuke Konishi struct buffer_head, b_assoc_buffers);
15764b5a32eSRyusuke Konishi raw_sum = (struct nilfs_segment_summary *)bh_sum->b_data;
15864b5a32eSRyusuke Konishi
15964b5a32eSRyusuke Konishi raw_sum->ss_magic = cpu_to_le32(NILFS_SEGSUM_MAGIC);
16064b5a32eSRyusuke Konishi raw_sum->ss_bytes = cpu_to_le16(sizeof(*raw_sum));
16164b5a32eSRyusuke Konishi raw_sum->ss_flags = cpu_to_le16(segbuf->sb_sum.flags);
16264b5a32eSRyusuke Konishi raw_sum->ss_seq = cpu_to_le64(segbuf->sb_sum.seg_seq);
16364b5a32eSRyusuke Konishi raw_sum->ss_create = cpu_to_le64(segbuf->sb_sum.ctime);
16464b5a32eSRyusuke Konishi raw_sum->ss_next = cpu_to_le64(segbuf->sb_sum.next);
16564b5a32eSRyusuke Konishi raw_sum->ss_nblocks = cpu_to_le32(segbuf->sb_sum.nblocks);
16664b5a32eSRyusuke Konishi raw_sum->ss_nfinfo = cpu_to_le32(segbuf->sb_sum.nfinfo);
16764b5a32eSRyusuke Konishi raw_sum->ss_sumbytes = cpu_to_le32(segbuf->sb_sum.sumbytes);
16864b5a32eSRyusuke Konishi raw_sum->ss_pad = 0;
16950614bcfSRyusuke Konishi raw_sum->ss_cno = cpu_to_le64(segbuf->sb_sum.cno);
17064b5a32eSRyusuke Konishi }
17164b5a32eSRyusuke Konishi
17264b5a32eSRyusuke Konishi /*
17364b5a32eSRyusuke Konishi * CRC calculation routines
17464b5a32eSRyusuke Konishi */
175aaed1d5bSRyusuke Konishi static void
nilfs_segbuf_fill_in_segsum_crc(struct nilfs_segment_buffer * segbuf,u32 seed)176aaed1d5bSRyusuke Konishi nilfs_segbuf_fill_in_segsum_crc(struct nilfs_segment_buffer *segbuf, u32 seed)
17764b5a32eSRyusuke Konishi {
17864b5a32eSRyusuke Konishi struct buffer_head *bh;
17964b5a32eSRyusuke Konishi struct nilfs_segment_summary *raw_sum;
18064b5a32eSRyusuke Konishi unsigned long size, bytes = segbuf->sb_sum.sumbytes;
18164b5a32eSRyusuke Konishi u32 crc;
18264b5a32eSRyusuke Konishi
18364b5a32eSRyusuke Konishi bh = list_entry(segbuf->sb_segsum_buffers.next, struct buffer_head,
18464b5a32eSRyusuke Konishi b_assoc_buffers);
18564b5a32eSRyusuke Konishi
18664b5a32eSRyusuke Konishi raw_sum = (struct nilfs_segment_summary *)bh->b_data;
18764b5a32eSRyusuke Konishi size = min_t(unsigned long, bytes, bh->b_size);
18864b5a32eSRyusuke Konishi crc = crc32_le(seed,
18964b5a32eSRyusuke Konishi (unsigned char *)raw_sum +
19064b5a32eSRyusuke Konishi sizeof(raw_sum->ss_datasum) + sizeof(raw_sum->ss_sumsum),
19164b5a32eSRyusuke Konishi size - (sizeof(raw_sum->ss_datasum) +
19264b5a32eSRyusuke Konishi sizeof(raw_sum->ss_sumsum)));
19364b5a32eSRyusuke Konishi
19464b5a32eSRyusuke Konishi list_for_each_entry_continue(bh, &segbuf->sb_segsum_buffers,
19564b5a32eSRyusuke Konishi b_assoc_buffers) {
19664b5a32eSRyusuke Konishi bytes -= size;
19764b5a32eSRyusuke Konishi size = min_t(unsigned long, bytes, bh->b_size);
19864b5a32eSRyusuke Konishi crc = crc32_le(crc, bh->b_data, size);
19964b5a32eSRyusuke Konishi }
20064b5a32eSRyusuke Konishi raw_sum->ss_sumsum = cpu_to_le32(crc);
20164b5a32eSRyusuke Konishi }
20264b5a32eSRyusuke Konishi
nilfs_segbuf_fill_in_data_crc(struct nilfs_segment_buffer * segbuf,u32 seed)203aaed1d5bSRyusuke Konishi static void nilfs_segbuf_fill_in_data_crc(struct nilfs_segment_buffer *segbuf,
20464b5a32eSRyusuke Konishi u32 seed)
20564b5a32eSRyusuke Konishi {
20664b5a32eSRyusuke Konishi struct buffer_head *bh;
20764b5a32eSRyusuke Konishi struct nilfs_segment_summary *raw_sum;
20864b5a32eSRyusuke Konishi void *kaddr;
20964b5a32eSRyusuke Konishi u32 crc;
21064b5a32eSRyusuke Konishi
21164b5a32eSRyusuke Konishi bh = list_entry(segbuf->sb_segsum_buffers.next, struct buffer_head,
21264b5a32eSRyusuke Konishi b_assoc_buffers);
21364b5a32eSRyusuke Konishi raw_sum = (struct nilfs_segment_summary *)bh->b_data;
21464b5a32eSRyusuke Konishi crc = crc32_le(seed,
21564b5a32eSRyusuke Konishi (unsigned char *)raw_sum + sizeof(raw_sum->ss_datasum),
21664b5a32eSRyusuke Konishi bh->b_size - sizeof(raw_sum->ss_datasum));
21764b5a32eSRyusuke Konishi
21864b5a32eSRyusuke Konishi list_for_each_entry_continue(bh, &segbuf->sb_segsum_buffers,
21964b5a32eSRyusuke Konishi b_assoc_buffers) {
22064b5a32eSRyusuke Konishi crc = crc32_le(crc, bh->b_data, bh->b_size);
22164b5a32eSRyusuke Konishi }
22264b5a32eSRyusuke Konishi list_for_each_entry(bh, &segbuf->sb_payload_buffers, b_assoc_buffers) {
2237b9c0976SCong Wang kaddr = kmap_atomic(bh->b_page);
22464b5a32eSRyusuke Konishi crc = crc32_le(crc, kaddr + bh_offset(bh), bh->b_size);
2257b9c0976SCong Wang kunmap_atomic(kaddr);
22664b5a32eSRyusuke Konishi }
22764b5a32eSRyusuke Konishi raw_sum->ss_datasum = cpu_to_le32(crc);
22864b5a32eSRyusuke Konishi }
22964b5a32eSRyusuke Konishi
230aaed1d5bSRyusuke Konishi static void
nilfs_segbuf_fill_in_super_root_crc(struct nilfs_segment_buffer * segbuf,u32 seed)231aaed1d5bSRyusuke Konishi nilfs_segbuf_fill_in_super_root_crc(struct nilfs_segment_buffer *segbuf,
232aaed1d5bSRyusuke Konishi u32 seed)
233aaed1d5bSRyusuke Konishi {
234aaed1d5bSRyusuke Konishi struct nilfs_super_root *raw_sr;
2356c6de1aaSRyusuke Konishi struct the_nilfs *nilfs = segbuf->sb_super->s_fs_info;
2360c6c44cbSRyusuke Konishi unsigned int srsize;
237aaed1d5bSRyusuke Konishi u32 crc;
238aaed1d5bSRyusuke Konishi
239aaed1d5bSRyusuke Konishi raw_sr = (struct nilfs_super_root *)segbuf->sb_super_root->b_data;
2406c6de1aaSRyusuke Konishi srsize = NILFS_SR_BYTES(nilfs->ns_inode_size);
241aaed1d5bSRyusuke Konishi crc = crc32_le(seed,
242aaed1d5bSRyusuke Konishi (unsigned char *)raw_sr + sizeof(raw_sr->sr_sum),
2436c6de1aaSRyusuke Konishi srsize - sizeof(raw_sr->sr_sum));
244aaed1d5bSRyusuke Konishi raw_sr->sr_sum = cpu_to_le32(crc);
245aaed1d5bSRyusuke Konishi }
246aaed1d5bSRyusuke Konishi
nilfs_release_buffers(struct list_head * list)247e29df395SRyusuke Konishi static void nilfs_release_buffers(struct list_head *list)
24864b5a32eSRyusuke Konishi {
24964b5a32eSRyusuke Konishi struct buffer_head *bh, *n;
25064b5a32eSRyusuke Konishi
25164b5a32eSRyusuke Konishi list_for_each_entry_safe(bh, n, list, b_assoc_buffers) {
25264b5a32eSRyusuke Konishi list_del_init(&bh->b_assoc_buffers);
25364b5a32eSRyusuke Konishi brelse(bh);
25464b5a32eSRyusuke Konishi }
25564b5a32eSRyusuke Konishi }
25664b5a32eSRyusuke Konishi
nilfs_segbuf_clear(struct nilfs_segment_buffer * segbuf)257e29df395SRyusuke Konishi static void nilfs_segbuf_clear(struct nilfs_segment_buffer *segbuf)
258e29df395SRyusuke Konishi {
259e29df395SRyusuke Konishi nilfs_release_buffers(&segbuf->sb_segsum_buffers);
260e29df395SRyusuke Konishi nilfs_release_buffers(&segbuf->sb_payload_buffers);
2611e2b68bfSRyusuke Konishi segbuf->sb_super_root = NULL;
262e29df395SRyusuke Konishi }
263e29df395SRyusuke Konishi
264e29df395SRyusuke Konishi /*
265e29df395SRyusuke Konishi * Iterators for segment buffers
266e29df395SRyusuke Konishi */
nilfs_clear_logs(struct list_head * logs)267e29df395SRyusuke Konishi void nilfs_clear_logs(struct list_head *logs)
268e29df395SRyusuke Konishi {
269e29df395SRyusuke Konishi struct nilfs_segment_buffer *segbuf;
270e29df395SRyusuke Konishi
271e29df395SRyusuke Konishi list_for_each_entry(segbuf, logs, sb_list)
272e29df395SRyusuke Konishi nilfs_segbuf_clear(segbuf);
273e29df395SRyusuke Konishi }
274e29df395SRyusuke Konishi
nilfs_truncate_logs(struct list_head * logs,struct nilfs_segment_buffer * last)275e29df395SRyusuke Konishi void nilfs_truncate_logs(struct list_head *logs,
276e29df395SRyusuke Konishi struct nilfs_segment_buffer *last)
277e29df395SRyusuke Konishi {
278e29df395SRyusuke Konishi struct nilfs_segment_buffer *n, *segbuf;
279e29df395SRyusuke Konishi
280e29df395SRyusuke Konishi segbuf = list_prepare_entry(last, logs, sb_list);
281e29df395SRyusuke Konishi list_for_each_entry_safe_continue(segbuf, n, logs, sb_list) {
282e29df395SRyusuke Konishi list_del_init(&segbuf->sb_list);
283e29df395SRyusuke Konishi nilfs_segbuf_clear(segbuf);
284e29df395SRyusuke Konishi nilfs_segbuf_free(segbuf);
285e29df395SRyusuke Konishi }
286e29df395SRyusuke Konishi }
287e29df395SRyusuke Konishi
nilfs_write_logs(struct list_head * logs,struct the_nilfs * nilfs)288d1c6b72aSRyusuke Konishi int nilfs_write_logs(struct list_head *logs, struct the_nilfs *nilfs)
289d1c6b72aSRyusuke Konishi {
290d1c6b72aSRyusuke Konishi struct nilfs_segment_buffer *segbuf;
291d1c6b72aSRyusuke Konishi int ret = 0;
292d1c6b72aSRyusuke Konishi
293d1c6b72aSRyusuke Konishi list_for_each_entry(segbuf, logs, sb_list) {
294d1c6b72aSRyusuke Konishi ret = nilfs_segbuf_write(segbuf, nilfs);
295d1c6b72aSRyusuke Konishi if (ret)
296d1c6b72aSRyusuke Konishi break;
297d1c6b72aSRyusuke Konishi }
298d1c6b72aSRyusuke Konishi return ret;
299d1c6b72aSRyusuke Konishi }
300d1c6b72aSRyusuke Konishi
nilfs_wait_on_logs(struct list_head * logs)301e29df395SRyusuke Konishi int nilfs_wait_on_logs(struct list_head *logs)
302e29df395SRyusuke Konishi {
303e29df395SRyusuke Konishi struct nilfs_segment_buffer *segbuf;
304d067633bSRyusuke Konishi int err, ret = 0;
305e29df395SRyusuke Konishi
306e29df395SRyusuke Konishi list_for_each_entry(segbuf, logs, sb_list) {
307e29df395SRyusuke Konishi err = nilfs_segbuf_wait(segbuf);
308d067633bSRyusuke Konishi if (err && !ret)
309d067633bSRyusuke Konishi ret = err;
310e29df395SRyusuke Konishi }
311d067633bSRyusuke Konishi return ret;
312e29df395SRyusuke Konishi }
313e29df395SRyusuke Konishi
314aaed1d5bSRyusuke Konishi /**
315aaed1d5bSRyusuke Konishi * nilfs_add_checksums_on_logs - add checksums on the logs
316aaed1d5bSRyusuke Konishi * @logs: list of segment buffers storing target logs
317aaed1d5bSRyusuke Konishi * @seed: checksum seed value
318aaed1d5bSRyusuke Konishi */
nilfs_add_checksums_on_logs(struct list_head * logs,u32 seed)319aaed1d5bSRyusuke Konishi void nilfs_add_checksums_on_logs(struct list_head *logs, u32 seed)
320aaed1d5bSRyusuke Konishi {
321aaed1d5bSRyusuke Konishi struct nilfs_segment_buffer *segbuf;
322aaed1d5bSRyusuke Konishi
323aaed1d5bSRyusuke Konishi list_for_each_entry(segbuf, logs, sb_list) {
324aaed1d5bSRyusuke Konishi if (segbuf->sb_super_root)
325aaed1d5bSRyusuke Konishi nilfs_segbuf_fill_in_super_root_crc(segbuf, seed);
326aaed1d5bSRyusuke Konishi nilfs_segbuf_fill_in_segsum_crc(segbuf, seed);
327aaed1d5bSRyusuke Konishi nilfs_segbuf_fill_in_data_crc(segbuf, seed);
328aaed1d5bSRyusuke Konishi }
329aaed1d5bSRyusuke Konishi }
330aaed1d5bSRyusuke Konishi
33164b5a32eSRyusuke Konishi /*
33264b5a32eSRyusuke Konishi * BIO operations
33364b5a32eSRyusuke Konishi */
nilfs_end_bio_write(struct bio * bio)3344246a0b6SChristoph Hellwig static void nilfs_end_bio_write(struct bio *bio)
33564b5a32eSRyusuke Konishi {
3369284ad2aSRyusuke Konishi struct nilfs_segment_buffer *segbuf = bio->bi_private;
33764b5a32eSRyusuke Konishi
3384e4cbee9SChristoph Hellwig if (bio->bi_status)
3399284ad2aSRyusuke Konishi atomic_inc(&segbuf->sb_err);
34064b5a32eSRyusuke Konishi
34164b5a32eSRyusuke Konishi bio_put(bio);
3429284ad2aSRyusuke Konishi complete(&segbuf->sb_bio_event);
34364b5a32eSRyusuke Konishi }
34464b5a32eSRyusuke Konishi
nilfs_segbuf_submit_bio(struct nilfs_segment_buffer * segbuf,struct nilfs_write_info * wi)3459284ad2aSRyusuke Konishi static int nilfs_segbuf_submit_bio(struct nilfs_segment_buffer *segbuf,
346fbe7c2efSChristoph Hellwig struct nilfs_write_info *wi)
34764b5a32eSRyusuke Konishi {
34864b5a32eSRyusuke Konishi struct bio *bio = wi->bio;
34964b5a32eSRyusuke Konishi
35064b5a32eSRyusuke Konishi bio->bi_end_io = nilfs_end_bio_write;
3519284ad2aSRyusuke Konishi bio->bi_private = segbuf;
3524e49ea4aSMike Christie submit_bio(bio);
3534bf93b50SVyacheslav Dubeyko segbuf->sb_nbio++;
35464b5a32eSRyusuke Konishi
35564b5a32eSRyusuke Konishi wi->bio = NULL;
35664b5a32eSRyusuke Konishi wi->rest_blocks -= wi->end - wi->start;
35764b5a32eSRyusuke Konishi wi->nr_vecs = min(wi->max_pages, wi->rest_blocks);
35864b5a32eSRyusuke Konishi wi->start = wi->end;
35964b5a32eSRyusuke Konishi return 0;
36064b5a32eSRyusuke Konishi }
36164b5a32eSRyusuke Konishi
nilfs_segbuf_prepare_write(struct nilfs_segment_buffer * segbuf,struct nilfs_write_info * wi)3629c965bacSRyusuke Konishi static void nilfs_segbuf_prepare_write(struct nilfs_segment_buffer *segbuf,
36364b5a32eSRyusuke Konishi struct nilfs_write_info *wi)
36464b5a32eSRyusuke Konishi {
36564b5a32eSRyusuke Konishi wi->bio = NULL;
36664b5a32eSRyusuke Konishi wi->rest_blocks = segbuf->sb_sum.nblocks;
367a8affc03SChristoph Hellwig wi->max_pages = BIO_MAX_VECS;
36864b5a32eSRyusuke Konishi wi->nr_vecs = min(wi->max_pages, wi->rest_blocks);
36964b5a32eSRyusuke Konishi wi->start = wi->end = 0;
37064b5a32eSRyusuke Konishi wi->blocknr = segbuf->sb_pseg_start;
37164b5a32eSRyusuke Konishi }
37264b5a32eSRyusuke Konishi
nilfs_segbuf_submit_bh(struct nilfs_segment_buffer * segbuf,struct nilfs_write_info * wi,struct buffer_head * bh)3739284ad2aSRyusuke Konishi static int nilfs_segbuf_submit_bh(struct nilfs_segment_buffer *segbuf,
3749284ad2aSRyusuke Konishi struct nilfs_write_info *wi,
375fbe7c2efSChristoph Hellwig struct buffer_head *bh)
37664b5a32eSRyusuke Konishi {
37764b5a32eSRyusuke Konishi int len, err;
37864b5a32eSRyusuke Konishi
37964b5a32eSRyusuke Konishi BUG_ON(wi->nr_vecs <= 0);
38064b5a32eSRyusuke Konishi repeat:
38164b5a32eSRyusuke Konishi if (!wi->bio) {
382fbe7c2efSChristoph Hellwig wi->bio = bio_alloc(wi->nilfs->ns_bdev, wi->nr_vecs,
383fbe7c2efSChristoph Hellwig REQ_OP_WRITE, GFP_NOIO);
384f0d91192SChristoph Hellwig wi->bio->bi_iter.bi_sector = (wi->blocknr + wi->end) <<
385f0d91192SChristoph Hellwig (wi->nilfs->ns_blocksize_bits - 9);
38664b5a32eSRyusuke Konishi }
38764b5a32eSRyusuke Konishi
38864b5a32eSRyusuke Konishi len = bio_add_page(wi->bio, bh->b_page, bh->b_size, bh_offset(bh));
38964b5a32eSRyusuke Konishi if (len == bh->b_size) {
39064b5a32eSRyusuke Konishi wi->end++;
39164b5a32eSRyusuke Konishi return 0;
39264b5a32eSRyusuke Konishi }
39364b5a32eSRyusuke Konishi /* bio is FULL */
394fbe7c2efSChristoph Hellwig err = nilfs_segbuf_submit_bio(segbuf, wi);
39564b5a32eSRyusuke Konishi /* never submit current bh */
39664b5a32eSRyusuke Konishi if (likely(!err))
39764b5a32eSRyusuke Konishi goto repeat;
39864b5a32eSRyusuke Konishi return err;
39964b5a32eSRyusuke Konishi }
40064b5a32eSRyusuke Konishi
4019c965bacSRyusuke Konishi /**
4029c965bacSRyusuke Konishi * nilfs_segbuf_write - submit write requests of a log
4039c965bacSRyusuke Konishi * @segbuf: buffer storing a log to be written
4049c965bacSRyusuke Konishi * @nilfs: nilfs object
4059c965bacSRyusuke Konishi *
4069c965bacSRyusuke Konishi * Return Value: On Success, 0 is returned. On Error, one of the following
4079c965bacSRyusuke Konishi * negative error code is returned.
4089c965bacSRyusuke Konishi *
4099c965bacSRyusuke Konishi * %-EIO - I/O error
4109c965bacSRyusuke Konishi *
4119c965bacSRyusuke Konishi * %-ENOMEM - Insufficient memory available.
4129c965bacSRyusuke Konishi */
nilfs_segbuf_write(struct nilfs_segment_buffer * segbuf,struct the_nilfs * nilfs)4136c477d44SRyusuke Konishi static int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf,
4149c965bacSRyusuke Konishi struct the_nilfs *nilfs)
41564b5a32eSRyusuke Konishi {
4169c965bacSRyusuke Konishi struct nilfs_write_info wi;
41764b5a32eSRyusuke Konishi struct buffer_head *bh;
418b2d45866SMike Christie int res = 0;
41964b5a32eSRyusuke Konishi
4209c965bacSRyusuke Konishi wi.nilfs = nilfs;
4219c965bacSRyusuke Konishi nilfs_segbuf_prepare_write(segbuf, &wi);
4229c965bacSRyusuke Konishi
42364b5a32eSRyusuke Konishi list_for_each_entry(bh, &segbuf->sb_segsum_buffers, b_assoc_buffers) {
424fbe7c2efSChristoph Hellwig res = nilfs_segbuf_submit_bh(segbuf, &wi, bh);
42564b5a32eSRyusuke Konishi if (unlikely(res))
42664b5a32eSRyusuke Konishi goto failed_bio;
42764b5a32eSRyusuke Konishi }
42864b5a32eSRyusuke Konishi
42964b5a32eSRyusuke Konishi list_for_each_entry(bh, &segbuf->sb_payload_buffers, b_assoc_buffers) {
430fbe7c2efSChristoph Hellwig res = nilfs_segbuf_submit_bh(segbuf, &wi, bh);
43164b5a32eSRyusuke Konishi if (unlikely(res))
43264b5a32eSRyusuke Konishi goto failed_bio;
43364b5a32eSRyusuke Konishi }
43464b5a32eSRyusuke Konishi
4359c965bacSRyusuke Konishi if (wi.bio) {
43664b5a32eSRyusuke Konishi /*
43764b5a32eSRyusuke Konishi * Last BIO is always sent through the following
43864b5a32eSRyusuke Konishi * submission.
43964b5a32eSRyusuke Konishi */
440fbe7c2efSChristoph Hellwig wi.bio->bi_opf |= REQ_SYNC;
441fbe7c2efSChristoph Hellwig res = nilfs_segbuf_submit_bio(segbuf, &wi);
44264b5a32eSRyusuke Konishi }
44364b5a32eSRyusuke Konishi
44464b5a32eSRyusuke Konishi failed_bio:
4455f1586d0SRyusuke Konishi return res;
44664b5a32eSRyusuke Konishi }
44764b5a32eSRyusuke Konishi
44864b5a32eSRyusuke Konishi /**
44964b5a32eSRyusuke Konishi * nilfs_segbuf_wait - wait for completion of requested BIOs
4509284ad2aSRyusuke Konishi * @segbuf: segment buffer
45164b5a32eSRyusuke Konishi *
45264b5a32eSRyusuke Konishi * Return Value: On Success, 0 is returned. On Error, one of the following
45364b5a32eSRyusuke Konishi * negative error code is returned.
45464b5a32eSRyusuke Konishi *
45564b5a32eSRyusuke Konishi * %-EIO - I/O error
45664b5a32eSRyusuke Konishi */
nilfs_segbuf_wait(struct nilfs_segment_buffer * segbuf)4576c477d44SRyusuke Konishi static int nilfs_segbuf_wait(struct nilfs_segment_buffer *segbuf)
45864b5a32eSRyusuke Konishi {
45964b5a32eSRyusuke Konishi int err = 0;
46064b5a32eSRyusuke Konishi
4619284ad2aSRyusuke Konishi if (!segbuf->sb_nbio)
46264b5a32eSRyusuke Konishi return 0;
46364b5a32eSRyusuke Konishi
46464b5a32eSRyusuke Konishi do {
4659284ad2aSRyusuke Konishi wait_for_completion(&segbuf->sb_bio_event);
4669284ad2aSRyusuke Konishi } while (--segbuf->sb_nbio > 0);
46764b5a32eSRyusuke Konishi
4689284ad2aSRyusuke Konishi if (unlikely(atomic_read(&segbuf->sb_err) > 0)) {
469a1d0747aSJoe Perches nilfs_err(segbuf->sb_super,
470feee880fSRyusuke Konishi "I/O error writing log (start-blocknr=%llu, block-count=%lu) in segment %llu",
471feee880fSRyusuke Konishi (unsigned long long)segbuf->sb_pseg_start,
472feee880fSRyusuke Konishi segbuf->sb_sum.nblocks,
473feee880fSRyusuke Konishi (unsigned long long)segbuf->sb_segnum);
47464b5a32eSRyusuke Konishi err = -EIO;
47564b5a32eSRyusuke Konishi }
47664b5a32eSRyusuke Konishi return err;
47764b5a32eSRyusuke Konishi }
478