brintos

brintos / linux-shallow public Read only

0
0
Text · 30.2 KiB · f0ce375 Raw
1149 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * NILFS checkpoint file.4 *5 * Copyright (C) 2006-2008 Nippon Telegraph and Telephone Corporation.6 *7 * Written by Koji Sato.8 */9 10#include <linux/kernel.h>11#include <linux/fs.h>12#include <linux/string.h>13#include <linux/buffer_head.h>14#include <linux/errno.h>15#include "mdt.h"16#include "cpfile.h"17 18 19static inline unsigned long20nilfs_cpfile_checkpoints_per_block(const struct inode *cpfile)21{22	return NILFS_MDT(cpfile)->mi_entries_per_block;23}24 25/* block number from the beginning of the file */26static unsigned long27nilfs_cpfile_get_blkoff(const struct inode *cpfile, __u64 cno)28{29	__u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1;30 31	tcno = div64_ul(tcno, nilfs_cpfile_checkpoints_per_block(cpfile));32	return (unsigned long)tcno;33}34 35/* offset in block */36static unsigned long37nilfs_cpfile_get_offset(const struct inode *cpfile, __u64 cno)38{39	__u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1;40 41	return do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile));42}43 44static __u64 nilfs_cpfile_first_checkpoint_in_block(const struct inode *cpfile,45						    unsigned long blkoff)46{47	return (__u64)nilfs_cpfile_checkpoints_per_block(cpfile) * blkoff48		+ 1 - NILFS_MDT(cpfile)->mi_first_entry_offset;49}50 51static unsigned long52nilfs_cpfile_checkpoints_in_block(const struct inode *cpfile,53				  __u64 curr,54				  __u64 max)55{56	return min_t(__u64,57		     nilfs_cpfile_checkpoints_per_block(cpfile) -58		     nilfs_cpfile_get_offset(cpfile, curr),59		     max - curr);60}61 62static inline int nilfs_cpfile_is_in_first(const struct inode *cpfile,63					   __u64 cno)64{65	return nilfs_cpfile_get_blkoff(cpfile, cno) == 0;66}67 68static unsigned int69nilfs_cpfile_block_add_valid_checkpoints(const struct inode *cpfile,70					 struct buffer_head *bh,71					 void *kaddr,72					 unsigned int n)73{74	struct nilfs_checkpoint *cp = kaddr + bh_offset(bh);75	unsigned int count;76 77	count = le32_to_cpu(cp->cp_checkpoints_count) + n;78	cp->cp_checkpoints_count = cpu_to_le32(count);79	return count;80}81 82static unsigned int83nilfs_cpfile_block_sub_valid_checkpoints(const struct inode *cpfile,84					 struct buffer_head *bh,85					 void *kaddr,86					 unsigned int n)87{88	struct nilfs_checkpoint *cp = kaddr + bh_offset(bh);89	unsigned int count;90 91	WARN_ON(le32_to_cpu(cp->cp_checkpoints_count) < n);92	count = le32_to_cpu(cp->cp_checkpoints_count) - n;93	cp->cp_checkpoints_count = cpu_to_le32(count);94	return count;95}96 97static inline struct nilfs_cpfile_header *98nilfs_cpfile_block_get_header(const struct inode *cpfile,99			      struct buffer_head *bh,100			      void *kaddr)101{102	return kaddr + bh_offset(bh);103}104 105static struct nilfs_checkpoint *106nilfs_cpfile_block_get_checkpoint(const struct inode *cpfile, __u64 cno,107				  struct buffer_head *bh,108				  void *kaddr)109{110	return kaddr + bh_offset(bh) + nilfs_cpfile_get_offset(cpfile, cno) *111		NILFS_MDT(cpfile)->mi_entry_size;112}113 114static void nilfs_cpfile_block_init(struct inode *cpfile,115				    struct buffer_head *bh,116				    void *kaddr)117{118	struct nilfs_checkpoint *cp = kaddr + bh_offset(bh);119	size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;120	int n = nilfs_cpfile_checkpoints_per_block(cpfile);121 122	while (n-- > 0) {123		nilfs_checkpoint_set_invalid(cp);124		cp = (void *)cp + cpsz;125	}126}127 128static int nilfs_cpfile_get_header_block(struct inode *cpfile,129					 struct buffer_head **bhp)130{131	int err = nilfs_mdt_get_block(cpfile, 0, 0, NULL, bhp);132 133	if (unlikely(err == -ENOENT)) {134		nilfs_error(cpfile->i_sb,135			    "missing header block in checkpoint metadata");136		err = -EIO;137	}138	return err;139}140 141static inline int nilfs_cpfile_get_checkpoint_block(struct inode *cpfile,142						    __u64 cno,143						    int create,144						    struct buffer_head **bhp)145{146	return nilfs_mdt_get_block(cpfile,147				   nilfs_cpfile_get_blkoff(cpfile, cno),148				   create, nilfs_cpfile_block_init, bhp);149}150 151/**152 * nilfs_cpfile_find_checkpoint_block - find and get a buffer on cpfile153 * @cpfile: inode of cpfile154 * @start_cno: start checkpoint number (inclusive)155 * @end_cno: end checkpoint number (inclusive)156 * @cnop: place to store the next checkpoint number157 * @bhp: place to store a pointer to buffer_head struct158 *159 * Return Value: On success, it returns 0. On error, the following negative160 * error code is returned.161 *162 * %-ENOMEM - Insufficient memory available.163 *164 * %-EIO - I/O error165 *166 * %-ENOENT - no block exists in the range.167 */168static int nilfs_cpfile_find_checkpoint_block(struct inode *cpfile,169					      __u64 start_cno, __u64 end_cno,170					      __u64 *cnop,171					      struct buffer_head **bhp)172{173	unsigned long start, end, blkoff;174	int ret;175 176	if (unlikely(start_cno > end_cno))177		return -ENOENT;178 179	start = nilfs_cpfile_get_blkoff(cpfile, start_cno);180	end = nilfs_cpfile_get_blkoff(cpfile, end_cno);181 182	ret = nilfs_mdt_find_block(cpfile, start, end, &blkoff, bhp);183	if (!ret)184		*cnop = (blkoff == start) ? start_cno :185			nilfs_cpfile_first_checkpoint_in_block(cpfile, blkoff);186	return ret;187}188 189static inline int nilfs_cpfile_delete_checkpoint_block(struct inode *cpfile,190						       __u64 cno)191{192	return nilfs_mdt_delete_block(cpfile,193				      nilfs_cpfile_get_blkoff(cpfile, cno));194}195 196/**197 * nilfs_cpfile_read_checkpoint - read a checkpoint entry in cpfile198 * @cpfile: checkpoint file inode199 * @cno:    number of checkpoint entry to read200 * @root:   nilfs root object201 * @ifile:  ifile's inode to read and attach to @root202 *203 * This function imports checkpoint information from the checkpoint file and204 * stores it to the inode file given by @ifile and the nilfs root object205 * given by @root.206 *207 * Return: 0 on success, or the following negative error code on failure.208 * * %-EINVAL	- Invalid checkpoint.209 * * %-ENOMEM	- Insufficient memory available.210 * * %-EIO	- I/O error (including metadata corruption).211 */212int nilfs_cpfile_read_checkpoint(struct inode *cpfile, __u64 cno,213				 struct nilfs_root *root, struct inode *ifile)214{215	struct buffer_head *cp_bh;216	struct nilfs_checkpoint *cp;217	void *kaddr;218	int ret;219 220	if (cno < 1 || cno > nilfs_mdt_cno(cpfile))221		return -EINVAL;222 223	down_read(&NILFS_MDT(cpfile)->mi_sem);224	ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);225	if (unlikely(ret < 0)) {226		if (ret == -ENOENT)227			ret = -EINVAL;228		goto out_sem;229	}230 231	kaddr = kmap_local_page(cp_bh->b_page);232	cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);233	if (nilfs_checkpoint_invalid(cp)) {234		ret = -EINVAL;235		goto put_cp;236	}237 238	ret = nilfs_read_inode_common(ifile, &cp->cp_ifile_inode);239	if (unlikely(ret)) {240		/*241		 * Since this inode is on a checkpoint entry, treat errors242		 * as metadata corruption.243		 */244		nilfs_err(cpfile->i_sb,245			  "ifile inode (checkpoint number=%llu) corrupted",246			  (unsigned long long)cno);247		ret = -EIO;248		goto put_cp;249	}250 251	/* Configure the nilfs root object */252	atomic64_set(&root->inodes_count, le64_to_cpu(cp->cp_inodes_count));253	atomic64_set(&root->blocks_count, le64_to_cpu(cp->cp_blocks_count));254	root->ifile = ifile;255 256put_cp:257	kunmap_local(kaddr);258	brelse(cp_bh);259out_sem:260	up_read(&NILFS_MDT(cpfile)->mi_sem);261	return ret;262}263 264/**265 * nilfs_cpfile_create_checkpoint - create a checkpoint entry on cpfile266 * @cpfile: checkpoint file inode267 * @cno:    number of checkpoint to set up268 *269 * This function creates a checkpoint with the number specified by @cno on270 * cpfile.  If the specified checkpoint entry already exists due to a past271 * failure, it will be reused without returning an error.272 * In either case, the buffer of the block containing the checkpoint entry273 * and the cpfile inode are made dirty for inclusion in the write log.274 *275 * Return: 0 on success, or the following negative error code on failure.276 * * %-ENOMEM	- Insufficient memory available.277 * * %-EIO	- I/O error (including metadata corruption).278 * * %-EROFS	- Read only filesystem279 */280int nilfs_cpfile_create_checkpoint(struct inode *cpfile, __u64 cno)281{282	struct buffer_head *header_bh, *cp_bh;283	struct nilfs_cpfile_header *header;284	struct nilfs_checkpoint *cp;285	void *kaddr;286	int ret;287 288	if (WARN_ON_ONCE(cno < 1))289		return -EIO;290 291	down_write(&NILFS_MDT(cpfile)->mi_sem);292	ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);293	if (unlikely(ret < 0))294		goto out_sem;295 296	ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 1, &cp_bh);297	if (unlikely(ret < 0))298		goto out_header;299 300	kaddr = kmap_local_page(cp_bh->b_page);301	cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);302	if (nilfs_checkpoint_invalid(cp)) {303		/* a newly-created checkpoint */304		nilfs_checkpoint_clear_invalid(cp);305		if (!nilfs_cpfile_is_in_first(cpfile, cno))306			nilfs_cpfile_block_add_valid_checkpoints(cpfile, cp_bh,307								 kaddr, 1);308		kunmap_local(kaddr);309 310		kaddr = kmap_local_page(header_bh->b_page);311		header = nilfs_cpfile_block_get_header(cpfile, header_bh,312						       kaddr);313		le64_add_cpu(&header->ch_ncheckpoints, 1);314		kunmap_local(kaddr);315		mark_buffer_dirty(header_bh);316	} else {317		kunmap_local(kaddr);318	}319 320	/* Force the buffer and the inode to become dirty */321	mark_buffer_dirty(cp_bh);322	brelse(cp_bh);323	nilfs_mdt_mark_dirty(cpfile);324 325out_header:326	brelse(header_bh);327 328out_sem:329	up_write(&NILFS_MDT(cpfile)->mi_sem);330	return ret;331}332 333/**334 * nilfs_cpfile_finalize_checkpoint - fill in a checkpoint entry in cpfile335 * @cpfile: checkpoint file inode336 * @cno:    checkpoint number337 * @root:   nilfs root object338 * @blkinc: number of blocks added by this checkpoint339 * @ctime:  checkpoint creation time340 * @minor:  minor checkpoint flag341 *342 * This function completes the checkpoint entry numbered by @cno in the343 * cpfile with the data given by the arguments @root, @blkinc, @ctime, and344 * @minor.345 *346 * Return: 0 on success, or the following negative error code on failure.347 * * %-ENOMEM	- Insufficient memory available.348 * * %-EIO	- I/O error (including metadata corruption).349 */350int nilfs_cpfile_finalize_checkpoint(struct inode *cpfile, __u64 cno,351				     struct nilfs_root *root, __u64 blkinc,352				     time64_t ctime, bool minor)353{354	struct buffer_head *cp_bh;355	struct nilfs_checkpoint *cp;356	void *kaddr;357	int ret;358 359	if (WARN_ON_ONCE(cno < 1))360		return -EIO;361 362	down_write(&NILFS_MDT(cpfile)->mi_sem);363	ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);364	if (unlikely(ret < 0)) {365		if (ret == -ENOENT)366			goto error;367		goto out_sem;368	}369 370	kaddr = kmap_local_page(cp_bh->b_page);371	cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);372	if (unlikely(nilfs_checkpoint_invalid(cp))) {373		kunmap_local(kaddr);374		brelse(cp_bh);375		goto error;376	}377 378	cp->cp_snapshot_list.ssl_next = 0;379	cp->cp_snapshot_list.ssl_prev = 0;380	cp->cp_inodes_count = cpu_to_le64(atomic64_read(&root->inodes_count));381	cp->cp_blocks_count = cpu_to_le64(atomic64_read(&root->blocks_count));382	cp->cp_nblk_inc = cpu_to_le64(blkinc);383	cp->cp_create = cpu_to_le64(ctime);384	cp->cp_cno = cpu_to_le64(cno);385 386	if (minor)387		nilfs_checkpoint_set_minor(cp);388	else389		nilfs_checkpoint_clear_minor(cp);390 391	nilfs_write_inode_common(root->ifile, &cp->cp_ifile_inode);392	nilfs_bmap_write(NILFS_I(root->ifile)->i_bmap, &cp->cp_ifile_inode);393 394	kunmap_local(kaddr);395	brelse(cp_bh);396out_sem:397	up_write(&NILFS_MDT(cpfile)->mi_sem);398	return ret;399 400error:401	nilfs_error(cpfile->i_sb,402		    "checkpoint finalization failed due to metadata corruption.");403	ret = -EIO;404	goto out_sem;405}406 407/**408 * nilfs_cpfile_delete_checkpoints - delete checkpoints409 * @cpfile: inode of checkpoint file410 * @start: start checkpoint number411 * @end: end checkpoint number412 *413 * Description: nilfs_cpfile_delete_checkpoints() deletes the checkpoints in414 * the period from @start to @end, excluding @end itself. The checkpoints415 * which have been already deleted are ignored.416 *417 * Return Value: On success, 0 is returned. On error, one of the following418 * negative error codes is returned.419 *420 * %-EIO - I/O error.421 *422 * %-ENOMEM - Insufficient amount of memory available.423 *424 * %-EINVAL - invalid checkpoints.425 */426int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,427				    __u64 start,428				    __u64 end)429{430	struct buffer_head *header_bh, *cp_bh;431	struct nilfs_cpfile_header *header;432	struct nilfs_checkpoint *cp;433	size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;434	__u64 cno;435	void *kaddr;436	unsigned long tnicps;437	int ret, ncps, nicps, nss, count, i;438 439	if (unlikely(start == 0 || start > end)) {440		nilfs_err(cpfile->i_sb,441			  "cannot delete checkpoints: invalid range [%llu, %llu)",442			  (unsigned long long)start, (unsigned long long)end);443		return -EINVAL;444	}445 446	down_write(&NILFS_MDT(cpfile)->mi_sem);447 448	ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);449	if (ret < 0)450		goto out_sem;451	tnicps = 0;452	nss = 0;453 454	for (cno = start; cno < end; cno += ncps) {455		ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, end);456		ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);457		if (ret < 0) {458			if (ret != -ENOENT)459				break;460			/* skip hole */461			ret = 0;462			continue;463		}464 465		kaddr = kmap_local_page(cp_bh->b_page);466		cp = nilfs_cpfile_block_get_checkpoint(467			cpfile, cno, cp_bh, kaddr);468		nicps = 0;469		for (i = 0; i < ncps; i++, cp = (void *)cp + cpsz) {470			if (nilfs_checkpoint_snapshot(cp)) {471				nss++;472			} else if (!nilfs_checkpoint_invalid(cp)) {473				nilfs_checkpoint_set_invalid(cp);474				nicps++;475			}476		}477		if (nicps > 0) {478			tnicps += nicps;479			mark_buffer_dirty(cp_bh);480			nilfs_mdt_mark_dirty(cpfile);481			if (!nilfs_cpfile_is_in_first(cpfile, cno)) {482				count =483				  nilfs_cpfile_block_sub_valid_checkpoints(484						cpfile, cp_bh, kaddr, nicps);485				if (count == 0) {486					/* make hole */487					kunmap_local(kaddr);488					brelse(cp_bh);489					ret =490					  nilfs_cpfile_delete_checkpoint_block(491								   cpfile, cno);492					if (ret == 0)493						continue;494					nilfs_err(cpfile->i_sb,495						  "error %d deleting checkpoint block",496						  ret);497					break;498				}499			}500		}501 502		kunmap_local(kaddr);503		brelse(cp_bh);504	}505 506	if (tnicps > 0) {507		kaddr = kmap_local_page(header_bh->b_page);508		header = nilfs_cpfile_block_get_header(cpfile, header_bh,509						       kaddr);510		le64_add_cpu(&header->ch_ncheckpoints, -(u64)tnicps);511		mark_buffer_dirty(header_bh);512		nilfs_mdt_mark_dirty(cpfile);513		kunmap_local(kaddr);514	}515 516	brelse(header_bh);517	if (nss > 0)518		ret = -EBUSY;519 520 out_sem:521	up_write(&NILFS_MDT(cpfile)->mi_sem);522	return ret;523}524 525static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile,526					      struct nilfs_checkpoint *cp,527					      struct nilfs_cpinfo *ci)528{529	ci->ci_flags = le32_to_cpu(cp->cp_flags);530	ci->ci_cno = le64_to_cpu(cp->cp_cno);531	ci->ci_create = le64_to_cpu(cp->cp_create);532	ci->ci_nblk_inc = le64_to_cpu(cp->cp_nblk_inc);533	ci->ci_inodes_count = le64_to_cpu(cp->cp_inodes_count);534	ci->ci_blocks_count = le64_to_cpu(cp->cp_blocks_count);535	ci->ci_next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);536}537 538static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop,539					  void *buf, unsigned int cisz,540					  size_t nci)541{542	struct nilfs_checkpoint *cp;543	struct nilfs_cpinfo *ci = buf;544	struct buffer_head *bh;545	size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;546	__u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop;547	void *kaddr;548	int n, ret;549	int ncps, i;550 551	if (cno == 0)552		return -ENOENT; /* checkpoint number 0 is invalid */553	down_read(&NILFS_MDT(cpfile)->mi_sem);554 555	for (n = 0; n < nci; cno += ncps) {556		ret = nilfs_cpfile_find_checkpoint_block(557			cpfile, cno, cur_cno - 1, &cno, &bh);558		if (ret < 0) {559			if (likely(ret == -ENOENT))560				break;561			goto out;562		}563		ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno);564 565		kaddr = kmap_local_page(bh->b_page);566		cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);567		for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) {568			if (!nilfs_checkpoint_invalid(cp)) {569				nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp,570								  ci);571				ci = (void *)ci + cisz;572				n++;573			}574		}575		kunmap_local(kaddr);576		brelse(bh);577	}578 579	ret = n;580	if (n > 0) {581		ci = (void *)ci - cisz;582		*cnop = ci->ci_cno + 1;583	}584 585 out:586	up_read(&NILFS_MDT(cpfile)->mi_sem);587	return ret;588}589 590static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,591					  void *buf, unsigned int cisz,592					  size_t nci)593{594	struct buffer_head *bh;595	struct nilfs_cpfile_header *header;596	struct nilfs_checkpoint *cp;597	struct nilfs_cpinfo *ci = buf;598	__u64 curr = *cnop, next;599	unsigned long curr_blkoff, next_blkoff;600	void *kaddr;601	int n = 0, ret;602 603	down_read(&NILFS_MDT(cpfile)->mi_sem);604 605	if (curr == 0) {606		ret = nilfs_cpfile_get_header_block(cpfile, &bh);607		if (ret < 0)608			goto out;609		kaddr = kmap_local_page(bh->b_page);610		header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);611		curr = le64_to_cpu(header->ch_snapshot_list.ssl_next);612		kunmap_local(kaddr);613		brelse(bh);614		if (curr == 0) {615			ret = 0;616			goto out;617		}618	} else if (unlikely(curr == ~(__u64)0)) {619		ret = 0;620		goto out;621	}622 623	curr_blkoff = nilfs_cpfile_get_blkoff(cpfile, curr);624	ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr, 0, &bh);625	if (unlikely(ret < 0)) {626		if (ret == -ENOENT)627			ret = 0; /* No snapshots (started from a hole block) */628		goto out;629	}630	kaddr = kmap_local_page(bh->b_page);631	while (n < nci) {632		cp = nilfs_cpfile_block_get_checkpoint(cpfile, curr, bh, kaddr);633		curr = ~(__u64)0; /* Terminator */634		if (unlikely(nilfs_checkpoint_invalid(cp) ||635			     !nilfs_checkpoint_snapshot(cp)))636			break;637		nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, ci);638		ci = (void *)ci + cisz;639		n++;640		next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);641		if (next == 0)642			break; /* reach end of the snapshot list */643 644		next_blkoff = nilfs_cpfile_get_blkoff(cpfile, next);645		if (curr_blkoff != next_blkoff) {646			kunmap_local(kaddr);647			brelse(bh);648			ret = nilfs_cpfile_get_checkpoint_block(cpfile, next,649								0, &bh);650			if (unlikely(ret < 0)) {651				WARN_ON(ret == -ENOENT);652				goto out;653			}654			kaddr = kmap_local_page(bh->b_page);655		}656		curr = next;657		curr_blkoff = next_blkoff;658	}659	kunmap_local(kaddr);660	brelse(bh);661	*cnop = curr;662	ret = n;663 664 out:665	up_read(&NILFS_MDT(cpfile)->mi_sem);666	return ret;667}668 669/**670 * nilfs_cpfile_get_cpinfo - get information on checkpoints671 * @cpfile: checkpoint file inode672 * @cnop:   place to pass a starting checkpoint number and receive a673 *          checkpoint number to continue the search674 * @mode:   mode of checkpoints that the caller wants to retrieve675 * @buf:    buffer for storing checkpoints' information676 * @cisz:   byte size of one checkpoint info item in array677 * @nci:    number of checkpoint info items to retrieve678 *679 * nilfs_cpfile_get_cpinfo() searches for checkpoints in @mode state680 * starting from the checkpoint number stored in @cnop, and stores681 * information about found checkpoints in @buf.682 * The buffer pointed to by @buf must be large enough to store information683 * for @nci checkpoints.  If at least one checkpoint information is684 * successfully retrieved, @cnop is updated to point to the checkpoint685 * number to continue searching.686 *687 * Return: Count of checkpoint info items stored in the output buffer on688 * success, or the following negative error code on failure.689 * * %-EINVAL	- Invalid checkpoint mode.690 * * %-ENOMEM	- Insufficient memory available.691 * * %-EIO	- I/O error (including metadata corruption).692 * * %-ENOENT	- Invalid checkpoint number specified.693 */694 695ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode,696				void *buf, unsigned int cisz, size_t nci)697{698	switch (mode) {699	case NILFS_CHECKPOINT:700		return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, buf, cisz, nci);701	case NILFS_SNAPSHOT:702		return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, buf, cisz, nci);703	default:704		return -EINVAL;705	}706}707 708/**709 * nilfs_cpfile_delete_checkpoint - delete a checkpoint710 * @cpfile: checkpoint file inode711 * @cno:    checkpoint number to delete712 *713 * Return: 0 on success, or the following negative error code on failure.714 * * %-EBUSY	- Checkpoint in use (snapshot specified).715 * * %-EIO	- I/O error (including metadata corruption).716 * * %-ENOENT	- No valid checkpoint found.717 * * %-ENOMEM	- Insufficient memory available.718 */719int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno)720{721	struct nilfs_cpinfo ci;722	__u64 tcno = cno;723	ssize_t nci;724 725	nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, sizeof(ci), 1);726	if (nci < 0)727		return nci;728	else if (nci == 0 || ci.ci_cno != cno)729		return -ENOENT;730	else if (nilfs_cpinfo_snapshot(&ci))731		return -EBUSY;732 733	return nilfs_cpfile_delete_checkpoints(cpfile, cno, cno + 1);734}735 736static struct nilfs_snapshot_list *737nilfs_cpfile_block_get_snapshot_list(const struct inode *cpfile,738				     __u64 cno,739				     struct buffer_head *bh,740				     void *kaddr)741{742	struct nilfs_cpfile_header *header;743	struct nilfs_checkpoint *cp;744	struct nilfs_snapshot_list *list;745 746	if (cno != 0) {747		cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);748		list = &cp->cp_snapshot_list;749	} else {750		header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);751		list = &header->ch_snapshot_list;752	}753	return list;754}755 756static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno)757{758	struct buffer_head *header_bh, *curr_bh, *prev_bh, *cp_bh;759	struct nilfs_cpfile_header *header;760	struct nilfs_checkpoint *cp;761	struct nilfs_snapshot_list *list;762	__u64 curr, prev;763	unsigned long curr_blkoff, prev_blkoff;764	void *kaddr;765	int ret;766 767	if (cno == 0)768		return -ENOENT; /* checkpoint number 0 is invalid */769	down_write(&NILFS_MDT(cpfile)->mi_sem);770 771	ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);772	if (ret < 0)773		goto out_sem;774	kaddr = kmap_local_page(cp_bh->b_page);775	cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);776	if (nilfs_checkpoint_invalid(cp)) {777		ret = -ENOENT;778		kunmap_local(kaddr);779		goto out_cp;780	}781	if (nilfs_checkpoint_snapshot(cp)) {782		ret = 0;783		kunmap_local(kaddr);784		goto out_cp;785	}786	kunmap_local(kaddr);787 788	ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);789	if (ret < 0)790		goto out_cp;791	kaddr = kmap_local_page(header_bh->b_page);792	header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);793	list = &header->ch_snapshot_list;794	curr_bh = header_bh;795	get_bh(curr_bh);796	curr = 0;797	curr_blkoff = 0;798	prev = le64_to_cpu(list->ssl_prev);799	while (prev > cno) {800		prev_blkoff = nilfs_cpfile_get_blkoff(cpfile, prev);801		curr = prev;802		if (curr_blkoff != prev_blkoff) {803			kunmap_local(kaddr);804			brelse(curr_bh);805			ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr,806								0, &curr_bh);807			if (ret < 0)808				goto out_header;809			kaddr = kmap_local_page(curr_bh->b_page);810		}811		curr_blkoff = prev_blkoff;812		cp = nilfs_cpfile_block_get_checkpoint(813			cpfile, curr, curr_bh, kaddr);814		list = &cp->cp_snapshot_list;815		prev = le64_to_cpu(list->ssl_prev);816	}817	kunmap_local(kaddr);818 819	if (prev != 0) {820		ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0,821							&prev_bh);822		if (ret < 0)823			goto out_curr;824	} else {825		prev_bh = header_bh;826		get_bh(prev_bh);827	}828 829	kaddr = kmap_local_page(curr_bh->b_page);830	list = nilfs_cpfile_block_get_snapshot_list(831		cpfile, curr, curr_bh, kaddr);832	list->ssl_prev = cpu_to_le64(cno);833	kunmap_local(kaddr);834 835	kaddr = kmap_local_page(cp_bh->b_page);836	cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);837	cp->cp_snapshot_list.ssl_next = cpu_to_le64(curr);838	cp->cp_snapshot_list.ssl_prev = cpu_to_le64(prev);839	nilfs_checkpoint_set_snapshot(cp);840	kunmap_local(kaddr);841 842	kaddr = kmap_local_page(prev_bh->b_page);843	list = nilfs_cpfile_block_get_snapshot_list(844		cpfile, prev, prev_bh, kaddr);845	list->ssl_next = cpu_to_le64(cno);846	kunmap_local(kaddr);847 848	kaddr = kmap_local_page(header_bh->b_page);849	header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);850	le64_add_cpu(&header->ch_nsnapshots, 1);851	kunmap_local(kaddr);852 853	mark_buffer_dirty(prev_bh);854	mark_buffer_dirty(curr_bh);855	mark_buffer_dirty(cp_bh);856	mark_buffer_dirty(header_bh);857	nilfs_mdt_mark_dirty(cpfile);858 859	brelse(prev_bh);860 861 out_curr:862	brelse(curr_bh);863 864 out_header:865	brelse(header_bh);866 867 out_cp:868	brelse(cp_bh);869 870 out_sem:871	up_write(&NILFS_MDT(cpfile)->mi_sem);872	return ret;873}874 875static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno)876{877	struct buffer_head *header_bh, *next_bh, *prev_bh, *cp_bh;878	struct nilfs_cpfile_header *header;879	struct nilfs_checkpoint *cp;880	struct nilfs_snapshot_list *list;881	__u64 next, prev;882	void *kaddr;883	int ret;884 885	if (cno == 0)886		return -ENOENT; /* checkpoint number 0 is invalid */887	down_write(&NILFS_MDT(cpfile)->mi_sem);888 889	ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);890	if (ret < 0)891		goto out_sem;892	kaddr = kmap_local_page(cp_bh->b_page);893	cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);894	if (nilfs_checkpoint_invalid(cp)) {895		ret = -ENOENT;896		kunmap_local(kaddr);897		goto out_cp;898	}899	if (!nilfs_checkpoint_snapshot(cp)) {900		ret = 0;901		kunmap_local(kaddr);902		goto out_cp;903	}904 905	list = &cp->cp_snapshot_list;906	next = le64_to_cpu(list->ssl_next);907	prev = le64_to_cpu(list->ssl_prev);908	kunmap_local(kaddr);909 910	ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);911	if (ret < 0)912		goto out_cp;913	if (next != 0) {914		ret = nilfs_cpfile_get_checkpoint_block(cpfile, next, 0,915							&next_bh);916		if (ret < 0)917			goto out_header;918	} else {919		next_bh = header_bh;920		get_bh(next_bh);921	}922	if (prev != 0) {923		ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0,924							&prev_bh);925		if (ret < 0)926			goto out_next;927	} else {928		prev_bh = header_bh;929		get_bh(prev_bh);930	}931 932	kaddr = kmap_local_page(next_bh->b_page);933	list = nilfs_cpfile_block_get_snapshot_list(934		cpfile, next, next_bh, kaddr);935	list->ssl_prev = cpu_to_le64(prev);936	kunmap_local(kaddr);937 938	kaddr = kmap_local_page(prev_bh->b_page);939	list = nilfs_cpfile_block_get_snapshot_list(940		cpfile, prev, prev_bh, kaddr);941	list->ssl_next = cpu_to_le64(next);942	kunmap_local(kaddr);943 944	kaddr = kmap_local_page(cp_bh->b_page);945	cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr);946	cp->cp_snapshot_list.ssl_next = cpu_to_le64(0);947	cp->cp_snapshot_list.ssl_prev = cpu_to_le64(0);948	nilfs_checkpoint_clear_snapshot(cp);949	kunmap_local(kaddr);950 951	kaddr = kmap_local_page(header_bh->b_page);952	header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr);953	le64_add_cpu(&header->ch_nsnapshots, -1);954	kunmap_local(kaddr);955 956	mark_buffer_dirty(next_bh);957	mark_buffer_dirty(prev_bh);958	mark_buffer_dirty(cp_bh);959	mark_buffer_dirty(header_bh);960	nilfs_mdt_mark_dirty(cpfile);961 962	brelse(prev_bh);963 964 out_next:965	brelse(next_bh);966 967 out_header:968	brelse(header_bh);969 970 out_cp:971	brelse(cp_bh);972 973 out_sem:974	up_write(&NILFS_MDT(cpfile)->mi_sem);975	return ret;976}977 978/**979 * nilfs_cpfile_is_snapshot - determine if checkpoint is a snapshot980 * @cpfile: inode of checkpoint file981 * @cno:    checkpoint number982 *983 * Return: 1 if the checkpoint specified by @cno is a snapshot, 0 if not, or984 * the following negative error code on failure.985 * * %-EIO	- I/O error (including metadata corruption).986 * * %-ENOENT	- No such checkpoint.987 * * %-ENOMEM	- Insufficient memory available.988 */989int nilfs_cpfile_is_snapshot(struct inode *cpfile, __u64 cno)990{991	struct buffer_head *bh;992	struct nilfs_checkpoint *cp;993	void *kaddr;994	int ret;995 996	/*997	 * CP number is invalid if it's zero or larger than the998	 * largest existing one.999	 */1000	if (cno == 0 || cno >= nilfs_mdt_cno(cpfile))1001		return -ENOENT;1002	down_read(&NILFS_MDT(cpfile)->mi_sem);1003 1004	ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh);1005	if (ret < 0)1006		goto out;1007	kaddr = kmap_local_page(bh->b_page);1008	cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr);1009	if (nilfs_checkpoint_invalid(cp))1010		ret = -ENOENT;1011	else1012		ret = nilfs_checkpoint_snapshot(cp);1013	kunmap_local(kaddr);1014	brelse(bh);1015 1016 out:1017	up_read(&NILFS_MDT(cpfile)->mi_sem);1018	return ret;1019}1020 1021/**1022 * nilfs_cpfile_change_cpmode - change checkpoint mode1023 * @cpfile: inode of checkpoint file1024 * @cno: checkpoint number1025 * @mode: mode of checkpoint1026 *1027 * Description: nilfs_change_cpmode() changes the mode of the checkpoint1028 * specified by @cno. The mode @mode is NILFS_CHECKPOINT or NILFS_SNAPSHOT.1029 *1030 * Return Value: On success, 0 is returned. On error, one of the following1031 * negative error codes is returned.1032 *1033 * %-EIO - I/O error.1034 *1035 * %-ENOMEM - Insufficient amount of memory available.1036 *1037 * %-ENOENT - No such checkpoint.1038 */1039int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode)1040{1041	int ret;1042 1043	switch (mode) {1044	case NILFS_CHECKPOINT:1045		if (nilfs_checkpoint_is_mounted(cpfile->i_sb, cno))1046			/*1047			 * Current implementation does not have to protect1048			 * plain read-only mounts since they are exclusive1049			 * with a read/write mount and are protected from the1050			 * cleaner.1051			 */1052			ret = -EBUSY;1053		else1054			ret = nilfs_cpfile_clear_snapshot(cpfile, cno);1055		return ret;1056	case NILFS_SNAPSHOT:1057		return nilfs_cpfile_set_snapshot(cpfile, cno);1058	default:1059		return -EINVAL;1060	}1061}1062 1063/**1064 * nilfs_cpfile_get_stat - get checkpoint statistics1065 * @cpfile: inode of checkpoint file1066 * @cpstat: pointer to a structure of checkpoint statistics1067 *1068 * Description: nilfs_cpfile_get_stat() returns information about checkpoints.1069 *1070 * Return Value: On success, 0 is returned, and checkpoints information is1071 * stored in the place pointed by @cpstat. On error, one of the following1072 * negative error codes is returned.1073 *1074 * %-EIO - I/O error.1075 *1076 * %-ENOMEM - Insufficient amount of memory available.1077 */1078int nilfs_cpfile_get_stat(struct inode *cpfile, struct nilfs_cpstat *cpstat)1079{1080	struct buffer_head *bh;1081	struct nilfs_cpfile_header *header;1082	void *kaddr;1083	int ret;1084 1085	down_read(&NILFS_MDT(cpfile)->mi_sem);1086 1087	ret = nilfs_cpfile_get_header_block(cpfile, &bh);1088	if (ret < 0)1089		goto out_sem;1090	kaddr = kmap_local_page(bh->b_page);1091	header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr);1092	cpstat->cs_cno = nilfs_mdt_cno(cpfile);1093	cpstat->cs_ncps = le64_to_cpu(header->ch_ncheckpoints);1094	cpstat->cs_nsss = le64_to_cpu(header->ch_nsnapshots);1095	kunmap_local(kaddr);1096	brelse(bh);1097 1098 out_sem:1099	up_read(&NILFS_MDT(cpfile)->mi_sem);1100	return ret;1101}1102 1103/**1104 * nilfs_cpfile_read - read or get cpfile inode1105 * @sb: super block instance1106 * @cpsize: size of a checkpoint entry1107 * @raw_inode: on-disk cpfile inode1108 * @inodep: buffer to store the inode1109 */1110int nilfs_cpfile_read(struct super_block *sb, size_t cpsize,1111		      struct nilfs_inode *raw_inode, struct inode **inodep)1112{1113	struct inode *cpfile;1114	int err;1115 1116	if (cpsize > sb->s_blocksize) {1117		nilfs_err(sb, "too large checkpoint size: %zu bytes", cpsize);1118		return -EINVAL;1119	} else if (cpsize < NILFS_MIN_CHECKPOINT_SIZE) {1120		nilfs_err(sb, "too small checkpoint size: %zu bytes", cpsize);1121		return -EINVAL;1122	}1123 1124	cpfile = nilfs_iget_locked(sb, NULL, NILFS_CPFILE_INO);1125	if (unlikely(!cpfile))1126		return -ENOMEM;1127	if (!(cpfile->i_state & I_NEW))1128		goto out;1129 1130	err = nilfs_mdt_init(cpfile, NILFS_MDT_GFP, 0);1131	if (err)1132		goto failed;1133 1134	nilfs_mdt_set_entry_size(cpfile, cpsize,1135				 sizeof(struct nilfs_cpfile_header));1136 1137	err = nilfs_read_inode_common(cpfile, raw_inode);1138	if (err)1139		goto failed;1140 1141	unlock_new_inode(cpfile);1142 out:1143	*inodep = cpfile;1144	return 0;1145 failed:1146	iget_failed(cpfile);1147	return err;1148}1149