brintos

brintos / linux-shallow public Read only

0
0
Text · 12.1 KiB · dc431b4 Raw
478 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * NILFS segment buffer4 *5 * Copyright (C) 2005-2008 Nippon Telegraph and Telephone Corporation.6 *7 * Written by Ryusuke Konishi.8 *9 */10 11#include <linux/buffer_head.h>12#include <linux/writeback.h>13#include <linux/crc32.h>14#include <linux/backing-dev.h>15#include <linux/slab.h>16#include "page.h"17#include "segbuf.h"18 19 20struct nilfs_write_info {21	struct the_nilfs       *nilfs;22	struct bio	       *bio;23	int			start, end; /* The region to be submitted */24	int			rest_blocks;25	int			max_pages;26	int			nr_vecs;27	sector_t		blocknr;28};29 30static int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf,31			      struct the_nilfs *nilfs);32static int nilfs_segbuf_wait(struct nilfs_segment_buffer *segbuf);33 34struct nilfs_segment_buffer *nilfs_segbuf_new(struct super_block *sb)35{36	struct nilfs_segment_buffer *segbuf;37 38	segbuf = kmem_cache_alloc(nilfs_segbuf_cachep, GFP_NOFS);39	if (unlikely(!segbuf))40		return NULL;41 42	segbuf->sb_super = sb;43	INIT_LIST_HEAD(&segbuf->sb_list);44	INIT_LIST_HEAD(&segbuf->sb_segsum_buffers);45	INIT_LIST_HEAD(&segbuf->sb_payload_buffers);46	segbuf->sb_super_root = NULL;47 48	init_completion(&segbuf->sb_bio_event);49	atomic_set(&segbuf->sb_err, 0);50	segbuf->sb_nbio = 0;51 52	return segbuf;53}54 55void nilfs_segbuf_free(struct nilfs_segment_buffer *segbuf)56{57	kmem_cache_free(nilfs_segbuf_cachep, segbuf);58}59 60void nilfs_segbuf_map(struct nilfs_segment_buffer *segbuf, __u64 segnum,61		     unsigned long offset, struct the_nilfs *nilfs)62{63	segbuf->sb_segnum = segnum;64	nilfs_get_segment_range(nilfs, segnum, &segbuf->sb_fseg_start,65				&segbuf->sb_fseg_end);66 67	segbuf->sb_pseg_start = segbuf->sb_fseg_start + offset;68	segbuf->sb_rest_blocks =69		segbuf->sb_fseg_end - segbuf->sb_pseg_start + 1;70}71 72/**73 * nilfs_segbuf_map_cont - map a new log behind a given log74 * @segbuf: new segment buffer75 * @prev: segment buffer containing a log to be continued76 */77void nilfs_segbuf_map_cont(struct nilfs_segment_buffer *segbuf,78			   struct nilfs_segment_buffer *prev)79{80	segbuf->sb_segnum = prev->sb_segnum;81	segbuf->sb_fseg_start = prev->sb_fseg_start;82	segbuf->sb_fseg_end = prev->sb_fseg_end;83	segbuf->sb_pseg_start = prev->sb_pseg_start + prev->sb_sum.nblocks;84	segbuf->sb_rest_blocks =85		segbuf->sb_fseg_end - segbuf->sb_pseg_start + 1;86}87 88void nilfs_segbuf_set_next_segnum(struct nilfs_segment_buffer *segbuf,89				  __u64 nextnum, struct the_nilfs *nilfs)90{91	segbuf->sb_nextnum = nextnum;92	segbuf->sb_sum.next = nilfs_get_segment_start_blocknr(nilfs, nextnum);93}94 95int nilfs_segbuf_extend_segsum(struct nilfs_segment_buffer *segbuf)96{97	struct buffer_head *bh;98 99	bh = sb_getblk(segbuf->sb_super,100		       segbuf->sb_pseg_start + segbuf->sb_sum.nsumblk);101	if (unlikely(!bh))102		return -ENOMEM;103 104	lock_buffer(bh);105	if (!buffer_uptodate(bh)) {106		memset(bh->b_data, 0, bh->b_size);107		set_buffer_uptodate(bh);108	}109	unlock_buffer(bh);110	nilfs_segbuf_add_segsum_buffer(segbuf, bh);111	return 0;112}113 114int nilfs_segbuf_extend_payload(struct nilfs_segment_buffer *segbuf,115				struct buffer_head **bhp)116{117	struct buffer_head *bh;118 119	bh = sb_getblk(segbuf->sb_super,120		       segbuf->sb_pseg_start + segbuf->sb_sum.nblocks);121	if (unlikely(!bh))122		return -ENOMEM;123 124	nilfs_segbuf_add_payload_buffer(segbuf, bh);125	*bhp = bh;126	return 0;127}128 129int nilfs_segbuf_reset(struct nilfs_segment_buffer *segbuf, unsigned int flags,130		       time64_t ctime, __u64 cno)131{132	int err;133 134	segbuf->sb_sum.nblocks = segbuf->sb_sum.nsumblk = 0;135	err = nilfs_segbuf_extend_segsum(segbuf);136	if (unlikely(err))137		return err;138 139	segbuf->sb_sum.flags = flags;140	segbuf->sb_sum.sumbytes = sizeof(struct nilfs_segment_summary);141	segbuf->sb_sum.nfinfo = segbuf->sb_sum.nfileblk = 0;142	segbuf->sb_sum.ctime = ctime;143	segbuf->sb_sum.cno = cno;144	return 0;145}146 147/*148 * Setup segment summary149 */150void nilfs_segbuf_fill_in_segsum(struct nilfs_segment_buffer *segbuf)151{152	struct nilfs_segment_summary *raw_sum;153	struct buffer_head *bh_sum;154 155	bh_sum = list_entry(segbuf->sb_segsum_buffers.next,156			    struct buffer_head, b_assoc_buffers);157	raw_sum = (struct nilfs_segment_summary *)bh_sum->b_data;158 159	raw_sum->ss_magic    = cpu_to_le32(NILFS_SEGSUM_MAGIC);160	raw_sum->ss_bytes    = cpu_to_le16(sizeof(*raw_sum));161	raw_sum->ss_flags    = cpu_to_le16(segbuf->sb_sum.flags);162	raw_sum->ss_seq      = cpu_to_le64(segbuf->sb_sum.seg_seq);163	raw_sum->ss_create   = cpu_to_le64(segbuf->sb_sum.ctime);164	raw_sum->ss_next     = cpu_to_le64(segbuf->sb_sum.next);165	raw_sum->ss_nblocks  = cpu_to_le32(segbuf->sb_sum.nblocks);166	raw_sum->ss_nfinfo   = cpu_to_le32(segbuf->sb_sum.nfinfo);167	raw_sum->ss_sumbytes = cpu_to_le32(segbuf->sb_sum.sumbytes);168	raw_sum->ss_pad      = 0;169	raw_sum->ss_cno      = cpu_to_le64(segbuf->sb_sum.cno);170}171 172/*173 * CRC calculation routines174 */175static void176nilfs_segbuf_fill_in_segsum_crc(struct nilfs_segment_buffer *segbuf, u32 seed)177{178	struct buffer_head *bh;179	struct nilfs_segment_summary *raw_sum;180	unsigned long size, bytes = segbuf->sb_sum.sumbytes;181	u32 crc;182 183	bh = list_entry(segbuf->sb_segsum_buffers.next, struct buffer_head,184			b_assoc_buffers);185 186	raw_sum = (struct nilfs_segment_summary *)bh->b_data;187	size = min_t(unsigned long, bytes, bh->b_size);188	crc = crc32_le(seed,189		       (unsigned char *)raw_sum +190		       sizeof(raw_sum->ss_datasum) + sizeof(raw_sum->ss_sumsum),191		       size - (sizeof(raw_sum->ss_datasum) +192			       sizeof(raw_sum->ss_sumsum)));193 194	list_for_each_entry_continue(bh, &segbuf->sb_segsum_buffers,195				     b_assoc_buffers) {196		bytes -= size;197		size = min_t(unsigned long, bytes, bh->b_size);198		crc = crc32_le(crc, bh->b_data, size);199	}200	raw_sum->ss_sumsum = cpu_to_le32(crc);201}202 203static void nilfs_segbuf_fill_in_data_crc(struct nilfs_segment_buffer *segbuf,204					  u32 seed)205{206	struct buffer_head *bh;207	struct nilfs_segment_summary *raw_sum;208	void *kaddr;209	u32 crc;210 211	bh = list_entry(segbuf->sb_segsum_buffers.next, struct buffer_head,212			b_assoc_buffers);213	raw_sum = (struct nilfs_segment_summary *)bh->b_data;214	crc = crc32_le(seed,215		       (unsigned char *)raw_sum + sizeof(raw_sum->ss_datasum),216		       bh->b_size - sizeof(raw_sum->ss_datasum));217 218	list_for_each_entry_continue(bh, &segbuf->sb_segsum_buffers,219				     b_assoc_buffers) {220		crc = crc32_le(crc, bh->b_data, bh->b_size);221	}222	list_for_each_entry(bh, &segbuf->sb_payload_buffers, b_assoc_buffers) {223		kaddr = kmap_local_page(bh->b_page);224		crc = crc32_le(crc, kaddr + bh_offset(bh), bh->b_size);225		kunmap_local(kaddr);226	}227	raw_sum->ss_datasum = cpu_to_le32(crc);228}229 230static void231nilfs_segbuf_fill_in_super_root_crc(struct nilfs_segment_buffer *segbuf,232				    u32 seed)233{234	struct nilfs_super_root *raw_sr;235	struct the_nilfs *nilfs = segbuf->sb_super->s_fs_info;236	unsigned int srsize;237	u32 crc;238 239	raw_sr = (struct nilfs_super_root *)segbuf->sb_super_root->b_data;240	srsize = NILFS_SR_BYTES(nilfs->ns_inode_size);241	crc = crc32_le(seed,242		       (unsigned char *)raw_sr + sizeof(raw_sr->sr_sum),243		       srsize - sizeof(raw_sr->sr_sum));244	raw_sr->sr_sum = cpu_to_le32(crc);245}246 247static void nilfs_release_buffers(struct list_head *list)248{249	struct buffer_head *bh, *n;250 251	list_for_each_entry_safe(bh, n, list, b_assoc_buffers) {252		list_del_init(&bh->b_assoc_buffers);253		brelse(bh);254	}255}256 257static void nilfs_segbuf_clear(struct nilfs_segment_buffer *segbuf)258{259	nilfs_release_buffers(&segbuf->sb_segsum_buffers);260	nilfs_release_buffers(&segbuf->sb_payload_buffers);261	segbuf->sb_super_root = NULL;262}263 264/*265 * Iterators for segment buffers266 */267void nilfs_clear_logs(struct list_head *logs)268{269	struct nilfs_segment_buffer *segbuf;270 271	list_for_each_entry(segbuf, logs, sb_list)272		nilfs_segbuf_clear(segbuf);273}274 275void nilfs_truncate_logs(struct list_head *logs,276			 struct nilfs_segment_buffer *last)277{278	struct nilfs_segment_buffer *n, *segbuf;279 280	segbuf = list_prepare_entry(last, logs, sb_list);281	list_for_each_entry_safe_continue(segbuf, n, logs, sb_list) {282		list_del_init(&segbuf->sb_list);283		nilfs_segbuf_clear(segbuf);284		nilfs_segbuf_free(segbuf);285	}286}287 288int nilfs_write_logs(struct list_head *logs, struct the_nilfs *nilfs)289{290	struct nilfs_segment_buffer *segbuf;291	int ret = 0;292 293	list_for_each_entry(segbuf, logs, sb_list) {294		ret = nilfs_segbuf_write(segbuf, nilfs);295		if (ret)296			break;297	}298	return ret;299}300 301int nilfs_wait_on_logs(struct list_head *logs)302{303	struct nilfs_segment_buffer *segbuf;304	int err, ret = 0;305 306	list_for_each_entry(segbuf, logs, sb_list) {307		err = nilfs_segbuf_wait(segbuf);308		if (err && !ret)309			ret = err;310	}311	return ret;312}313 314/**315 * nilfs_add_checksums_on_logs - add checksums on the logs316 * @logs: list of segment buffers storing target logs317 * @seed: checksum seed value318 */319void nilfs_add_checksums_on_logs(struct list_head *logs, u32 seed)320{321	struct nilfs_segment_buffer *segbuf;322 323	list_for_each_entry(segbuf, logs, sb_list) {324		if (segbuf->sb_super_root)325			nilfs_segbuf_fill_in_super_root_crc(segbuf, seed);326		nilfs_segbuf_fill_in_segsum_crc(segbuf, seed);327		nilfs_segbuf_fill_in_data_crc(segbuf, seed);328	}329}330 331/*332 * BIO operations333 */334static void nilfs_end_bio_write(struct bio *bio)335{336	struct nilfs_segment_buffer *segbuf = bio->bi_private;337 338	if (bio->bi_status)339		atomic_inc(&segbuf->sb_err);340 341	bio_put(bio);342	complete(&segbuf->sb_bio_event);343}344 345static int nilfs_segbuf_submit_bio(struct nilfs_segment_buffer *segbuf,346				   struct nilfs_write_info *wi)347{348	struct bio *bio = wi->bio;349 350	bio->bi_end_io = nilfs_end_bio_write;351	bio->bi_private = segbuf;352	submit_bio(bio);353	segbuf->sb_nbio++;354 355	wi->bio = NULL;356	wi->rest_blocks -= wi->end - wi->start;357	wi->nr_vecs = min(wi->max_pages, wi->rest_blocks);358	wi->start = wi->end;359	return 0;360}361 362static void nilfs_segbuf_prepare_write(struct nilfs_segment_buffer *segbuf,363				       struct nilfs_write_info *wi)364{365	wi->bio = NULL;366	wi->rest_blocks = segbuf->sb_sum.nblocks;367	wi->max_pages = BIO_MAX_VECS;368	wi->nr_vecs = min(wi->max_pages, wi->rest_blocks);369	wi->start = wi->end = 0;370	wi->blocknr = segbuf->sb_pseg_start;371}372 373static int nilfs_segbuf_submit_bh(struct nilfs_segment_buffer *segbuf,374				  struct nilfs_write_info *wi,375				  struct buffer_head *bh)376{377	int len, err;378 379	BUG_ON(wi->nr_vecs <= 0);380 repeat:381	if (!wi->bio) {382		wi->bio = bio_alloc(wi->nilfs->ns_bdev, wi->nr_vecs,383				    REQ_OP_WRITE, GFP_NOIO);384		wi->bio->bi_iter.bi_sector = (wi->blocknr + wi->end) <<385			(wi->nilfs->ns_blocksize_bits - 9);386	}387 388	len = bio_add_page(wi->bio, bh->b_page, bh->b_size, bh_offset(bh));389	if (len == bh->b_size) {390		wi->end++;391		return 0;392	}393	/* bio is FULL */394	err = nilfs_segbuf_submit_bio(segbuf, wi);395	/* never submit current bh */396	if (likely(!err))397		goto repeat;398	return err;399}400 401/**402 * nilfs_segbuf_write - submit write requests of a log403 * @segbuf: buffer storing a log to be written404 * @nilfs: nilfs object405 *406 * Return Value: On Success, 0 is returned. On Error, one of the following407 * negative error code is returned.408 *409 * %-EIO - I/O error410 *411 * %-ENOMEM - Insufficient memory available.412 */413static int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf,414			      struct the_nilfs *nilfs)415{416	struct nilfs_write_info wi;417	struct buffer_head *bh;418	int res = 0;419 420	wi.nilfs = nilfs;421	nilfs_segbuf_prepare_write(segbuf, &wi);422 423	list_for_each_entry(bh, &segbuf->sb_segsum_buffers, b_assoc_buffers) {424		res = nilfs_segbuf_submit_bh(segbuf, &wi, bh);425		if (unlikely(res))426			goto failed_bio;427	}428 429	list_for_each_entry(bh, &segbuf->sb_payload_buffers, b_assoc_buffers) {430		res = nilfs_segbuf_submit_bh(segbuf, &wi, bh);431		if (unlikely(res))432			goto failed_bio;433	}434 435	if (wi.bio) {436		/*437		 * Last BIO is always sent through the following438		 * submission.439		 */440		wi.bio->bi_opf |= REQ_SYNC;441		res = nilfs_segbuf_submit_bio(segbuf, &wi);442	}443 444 failed_bio:445	return res;446}447 448/**449 * nilfs_segbuf_wait - wait for completion of requested BIOs450 * @segbuf: segment buffer451 *452 * Return Value: On Success, 0 is returned. On Error, one of the following453 * negative error code is returned.454 *455 * %-EIO - I/O error456 */457static int nilfs_segbuf_wait(struct nilfs_segment_buffer *segbuf)458{459	int err = 0;460 461	if (!segbuf->sb_nbio)462		return 0;463 464	do {465		wait_for_completion(&segbuf->sb_bio_event);466	} while (--segbuf->sb_nbio > 0);467 468	if (unlikely(atomic_read(&segbuf->sb_err) > 0)) {469		nilfs_err(segbuf->sb_super,470			  "I/O error writing log (start-blocknr=%llu, block-count=%lu) in segment %llu",471			  (unsigned long long)segbuf->sb_pseg_start,472			  segbuf->sb_sum.nblocks,473			  (unsigned long long)segbuf->sb_segnum);474		err = -EIO;475	}476	return err;477}478