xref: /openbmc/linux/fs/nilfs2/segbuf.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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