File Index
Files and directories
Sign in
FILE

cpfile.c

File preview with syntax highlighting.

linux-6.19.14/fs/nilfs2/cpfile.c 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 long
  20nilfs_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 long
  27nilfs_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 long
  37nilfs_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) * blkoff
  48		+ 1 - NILFS_MDT(cpfile)->mi_first_entry_offset;
  49}
  50
  51static unsigned long
  52nilfs_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 int
  69nilfs_cpfile_block_add_valid_checkpoints(const struct inode *cpfile,
  70					 struct buffer_head *bh,
  71					 unsigned int n)
  72{
  73	struct nilfs_checkpoint *cp;
  74	unsigned int count;
  75
  76	cp = kmap_local_folio(bh->b_folio,
  77			      offset_in_folio(bh->b_folio, bh->b_data));
  78	count = le32_to_cpu(cp->cp_checkpoints_count) + n;
  79	cp->cp_checkpoints_count = cpu_to_le32(count);
  80	kunmap_local(cp);
  81	return count;
  82}
  83
  84static unsigned int
  85nilfs_cpfile_block_sub_valid_checkpoints(const struct inode *cpfile,
  86					 struct buffer_head *bh,
  87					 unsigned int n)
  88{
  89	struct nilfs_checkpoint *cp;
  90	unsigned int count;
  91
  92	cp = kmap_local_folio(bh->b_folio,
  93			      offset_in_folio(bh->b_folio, bh->b_data));
  94	WARN_ON(le32_to_cpu(cp->cp_checkpoints_count) < n);
  95	count = le32_to_cpu(cp->cp_checkpoints_count) - n;
  96	cp->cp_checkpoints_count = cpu_to_le32(count);
  97	kunmap_local(cp);
  98	return count;
  99}
 100
 101static void nilfs_cpfile_block_init(struct inode *cpfile,
 102				    struct buffer_head *bh,
 103				    void *from)
 104{
 105	struct nilfs_checkpoint *cp = from;
 106	size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
 107	int n = nilfs_cpfile_checkpoints_per_block(cpfile);
 108
 109	while (n-- > 0) {
 110		nilfs_checkpoint_set_invalid(cp);
 111		cp = (void *)cp + cpsz;
 112	}
 113}
 114
 115/**
 116 * nilfs_cpfile_checkpoint_offset - calculate the byte offset of a checkpoint
 117 *                                  entry in the folio containing it
 118 * @cpfile: checkpoint file inode
 119 * @cno:    checkpoint number
 120 * @bh:     buffer head of block containing checkpoint indexed by @cno
 121 *
 122 * Return: Byte offset in the folio of the checkpoint specified by @cno.
 123 */
 124static size_t nilfs_cpfile_checkpoint_offset(const struct inode *cpfile,
 125					     __u64 cno,
 126					     struct buffer_head *bh)
 127{
 128	return offset_in_folio(bh->b_folio, bh->b_data) +
 129		nilfs_cpfile_get_offset(cpfile, cno) *
 130		NILFS_MDT(cpfile)->mi_entry_size;
 131}
 132
 133/**
 134 * nilfs_cpfile_cp_snapshot_list_offset - calculate the byte offset of a
 135 *                                        checkpoint snapshot list in the folio
 136 *                                        containing it
 137 * @cpfile: checkpoint file inode
 138 * @cno:    checkpoint number
 139 * @bh:     buffer head of block containing checkpoint indexed by @cno
 140 *
 141 * Return: Byte offset in the folio of the checkpoint snapshot list specified
 142 *         by @cno.
 143 */
 144static size_t nilfs_cpfile_cp_snapshot_list_offset(const struct inode *cpfile,
 145						   __u64 cno,
 146						   struct buffer_head *bh)
 147{
 148	return nilfs_cpfile_checkpoint_offset(cpfile, cno, bh) +
 149		offsetof(struct nilfs_checkpoint, cp_snapshot_list);
 150}
 151
 152/**
 153 * nilfs_cpfile_ch_snapshot_list_offset - calculate the byte offset of the
 154 *                                        snapshot list in the header
 155 *
 156 * Return: Byte offset in the folio of the checkpoint snapshot list
 157 */
 158static size_t nilfs_cpfile_ch_snapshot_list_offset(void)
 159{
 160	return offsetof(struct nilfs_cpfile_header, ch_snapshot_list);
 161}
 162
 163static int nilfs_cpfile_get_header_block(struct inode *cpfile,
 164					 struct buffer_head **bhp)
 165{
 166	int err = nilfs_mdt_get_block(cpfile, 0, 0, NULL, bhp);
 167
 168	if (unlikely(err == -ENOENT)) {
 169		nilfs_error(cpfile->i_sb,
 170			    "missing header block in checkpoint metadata");
 171		err = -EIO;
 172	}
 173	return err;
 174}
 175
 176static inline int nilfs_cpfile_get_checkpoint_block(struct inode *cpfile,
 177						    __u64 cno,
 178						    int create,
 179						    struct buffer_head **bhp)
 180{
 181	return nilfs_mdt_get_block(cpfile,
 182				   nilfs_cpfile_get_blkoff(cpfile, cno),
 183				   create, nilfs_cpfile_block_init, bhp);
 184}
 185
 186/**
 187 * nilfs_cpfile_find_checkpoint_block - find and get a buffer on cpfile
 188 * @cpfile: inode of cpfile
 189 * @start_cno: start checkpoint number (inclusive)
 190 * @end_cno: end checkpoint number (inclusive)
 191 * @cnop: place to store the next checkpoint number
 192 * @bhp: place to store a pointer to buffer_head struct
 193 *
 194 * Return: 0 on success, or one of the following negative error codes on
 195 * failure:
 196 * * %-EIO	- I/O error (including metadata corruption).
 197 * * %-ENOENT	- no block exists in the range.
 198 * * %-ENOMEM	- Insufficient memory available.
 199 */
 200static int nilfs_cpfile_find_checkpoint_block(struct inode *cpfile,
 201					      __u64 start_cno, __u64 end_cno,
 202					      __u64 *cnop,
 203					      struct buffer_head **bhp)
 204{
 205	unsigned long start, end, blkoff;
 206	int ret;
 207
 208	if (unlikely(start_cno > end_cno))
 209		return -ENOENT;
 210
 211	start = nilfs_cpfile_get_blkoff(cpfile, start_cno);
 212	end = nilfs_cpfile_get_blkoff(cpfile, end_cno);
 213
 214	ret = nilfs_mdt_find_block(cpfile, start, end, &blkoff, bhp);
 215	if (!ret)
 216		*cnop = (blkoff == start) ? start_cno :
 217			nilfs_cpfile_first_checkpoint_in_block(cpfile, blkoff);
 218	return ret;
 219}
 220
 221static inline int nilfs_cpfile_delete_checkpoint_block(struct inode *cpfile,
 222						       __u64 cno)
 223{
 224	return nilfs_mdt_delete_block(cpfile,
 225				      nilfs_cpfile_get_blkoff(cpfile, cno));
 226}
 227
 228/**
 229 * nilfs_cpfile_read_checkpoint - read a checkpoint entry in cpfile
 230 * @cpfile: checkpoint file inode
 231 * @cno:    number of checkpoint entry to read
 232 * @root:   nilfs root object
 233 * @ifile:  ifile's inode to read and attach to @root
 234 *
 235 * This function imports checkpoint information from the checkpoint file and
 236 * stores it to the inode file given by @ifile and the nilfs root object
 237 * given by @root.
 238 *
 239 * Return: 0 on success, or one of the following negative error codes on
 240 * failure:
 241 * * %-EINVAL	- Invalid checkpoint.
 242 * * %-ENOMEM	- Insufficient memory available.
 243 * * %-EIO	- I/O error (including metadata corruption).
 244 */
 245int nilfs_cpfile_read_checkpoint(struct inode *cpfile, __u64 cno,
 246				 struct nilfs_root *root, struct inode *ifile)
 247{
 248	struct buffer_head *cp_bh;
 249	struct nilfs_checkpoint *cp;
 250	size_t offset;
 251	int ret;
 252
 253	if (cno < 1 || cno > nilfs_mdt_cno(cpfile))
 254		return -EINVAL;
 255
 256	down_read(&NILFS_MDT(cpfile)->mi_sem);
 257	ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
 258	if (unlikely(ret < 0)) {
 259		if (ret == -ENOENT)
 260			ret = -EINVAL;
 261		goto out_sem;
 262	}
 263
 264	offset = nilfs_cpfile_checkpoint_offset(cpfile, cno, cp_bh);
 265	cp = kmap_local_folio(cp_bh->b_folio, offset);
 266	if (nilfs_checkpoint_invalid(cp)) {
 267		ret = -EINVAL;
 268		goto put_cp;
 269	}
 270
 271	ret = nilfs_read_inode_common(ifile, &cp->cp_ifile_inode);
 272	if (unlikely(ret)) {
 273		/*
 274		 * Since this inode is on a checkpoint entry, treat errors
 275		 * as metadata corruption.
 276		 */
 277		nilfs_err(cpfile->i_sb,
 278			  "ifile inode (checkpoint number=%llu) corrupted",
 279			  (unsigned long long)cno);
 280		ret = -EIO;
 281		goto put_cp;
 282	}
 283
 284	/* Configure the nilfs root object */
 285	atomic64_set(&root->inodes_count, le64_to_cpu(cp->cp_inodes_count));
 286	atomic64_set(&root->blocks_count, le64_to_cpu(cp->cp_blocks_count));
 287	root->ifile = ifile;
 288
 289put_cp:
 290	kunmap_local(cp);
 291	brelse(cp_bh);
 292out_sem:
 293	up_read(&NILFS_MDT(cpfile)->mi_sem);
 294	return ret;
 295}
 296
 297/**
 298 * nilfs_cpfile_create_checkpoint - create a checkpoint entry on cpfile
 299 * @cpfile: checkpoint file inode
 300 * @cno:    number of checkpoint to set up
 301 *
 302 * This function creates a checkpoint with the number specified by @cno on
 303 * cpfile.  If the specified checkpoint entry already exists due to a past
 304 * failure, it will be reused without returning an error.
 305 * In either case, the buffer of the block containing the checkpoint entry
 306 * and the cpfile inode are made dirty for inclusion in the write log.
 307 *
 308 * Return: 0 on success, or one of the following negative error codes on
 309 * failure:
 310 * * %-ENOMEM	- Insufficient memory available.
 311 * * %-EIO	- I/O error (including metadata corruption).
 312 * * %-EROFS	- Read only filesystem
 313 */
 314int nilfs_cpfile_create_checkpoint(struct inode *cpfile, __u64 cno)
 315{
 316	struct buffer_head *header_bh, *cp_bh;
 317	struct nilfs_cpfile_header *header;
 318	struct nilfs_checkpoint *cp;
 319	size_t offset;
 320	int ret;
 321
 322	if (WARN_ON_ONCE(cno < 1))
 323		return -EIO;
 324
 325	down_write(&NILFS_MDT(cpfile)->mi_sem);
 326	ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
 327	if (unlikely(ret < 0))
 328		goto out_sem;
 329
 330	ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 1, &cp_bh);
 331	if (unlikely(ret < 0))
 332		goto out_header;
 333
 334	offset = nilfs_cpfile_checkpoint_offset(cpfile, cno, cp_bh);
 335	cp = kmap_local_folio(cp_bh->b_folio, offset);
 336	if (nilfs_checkpoint_invalid(cp)) {
 337		/* a newly-created checkpoint */
 338		nilfs_checkpoint_clear_invalid(cp);
 339		kunmap_local(cp);
 340		if (!nilfs_cpfile_is_in_first(cpfile, cno))
 341			nilfs_cpfile_block_add_valid_checkpoints(cpfile, cp_bh,
 342								 1);
 343
 344		header = kmap_local_folio(header_bh->b_folio, 0);
 345		le64_add_cpu(&header->ch_ncheckpoints, 1);
 346		kunmap_local(header);
 347		mark_buffer_dirty(header_bh);
 348	} else {
 349		kunmap_local(cp);
 350	}
 351
 352	/* Force the buffer and the inode to become dirty */
 353	mark_buffer_dirty(cp_bh);
 354	brelse(cp_bh);
 355	nilfs_mdt_mark_dirty(cpfile);
 356
 357out_header:
 358	brelse(header_bh);
 359
 360out_sem:
 361	up_write(&NILFS_MDT(cpfile)->mi_sem);
 362	return ret;
 363}
 364
 365/**
 366 * nilfs_cpfile_finalize_checkpoint - fill in a checkpoint entry in cpfile
 367 * @cpfile: checkpoint file inode
 368 * @cno:    checkpoint number
 369 * @root:   nilfs root object
 370 * @blkinc: number of blocks added by this checkpoint
 371 * @ctime:  checkpoint creation time
 372 * @minor:  minor checkpoint flag
 373 *
 374 * This function completes the checkpoint entry numbered by @cno in the
 375 * cpfile with the data given by the arguments @root, @blkinc, @ctime, and
 376 * @minor.
 377 *
 378 * Return: 0 on success, or one of the following negative error codes on
 379 * failure:
 380 * * %-ENOMEM	- Insufficient memory available.
 381 * * %-EIO	- I/O error (including metadata corruption).
 382 */
 383int nilfs_cpfile_finalize_checkpoint(struct inode *cpfile, __u64 cno,
 384				     struct nilfs_root *root, __u64 blkinc,
 385				     time64_t ctime, bool minor)
 386{
 387	struct buffer_head *cp_bh;
 388	struct nilfs_checkpoint *cp;
 389	size_t offset;
 390	int ret;
 391
 392	if (WARN_ON_ONCE(cno < 1))
 393		return -EIO;
 394
 395	down_write(&NILFS_MDT(cpfile)->mi_sem);
 396	ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
 397	if (unlikely(ret < 0)) {
 398		if (ret == -ENOENT)
 399			goto error;
 400		goto out_sem;
 401	}
 402
 403	offset = nilfs_cpfile_checkpoint_offset(cpfile, cno, cp_bh);
 404	cp = kmap_local_folio(cp_bh->b_folio, offset);
 405	if (unlikely(nilfs_checkpoint_invalid(cp))) {
 406		kunmap_local(cp);
 407		brelse(cp_bh);
 408		goto error;
 409	}
 410
 411	cp->cp_snapshot_list.ssl_next = 0;
 412	cp->cp_snapshot_list.ssl_prev = 0;
 413	cp->cp_inodes_count = cpu_to_le64(atomic64_read(&root->inodes_count));
 414	cp->cp_blocks_count = cpu_to_le64(atomic64_read(&root->blocks_count));
 415	cp->cp_nblk_inc = cpu_to_le64(blkinc);
 416	cp->cp_create = cpu_to_le64(ctime);
 417	cp->cp_cno = cpu_to_le64(cno);
 418
 419	if (minor)
 420		nilfs_checkpoint_set_minor(cp);
 421	else
 422		nilfs_checkpoint_clear_minor(cp);
 423
 424	nilfs_write_inode_common(root->ifile, &cp->cp_ifile_inode);
 425	nilfs_bmap_write(NILFS_I(root->ifile)->i_bmap, &cp->cp_ifile_inode);
 426
 427	kunmap_local(cp);
 428	brelse(cp_bh);
 429out_sem:
 430	up_write(&NILFS_MDT(cpfile)->mi_sem);
 431	return ret;
 432
 433error:
 434	nilfs_error(cpfile->i_sb,
 435		    "checkpoint finalization failed due to metadata corruption.");
 436	ret = -EIO;
 437	goto out_sem;
 438}
 439
 440/**
 441 * nilfs_cpfile_delete_checkpoints - delete checkpoints
 442 * @cpfile: inode of checkpoint file
 443 * @start: start checkpoint number
 444 * @end: end checkpoint number
 445 *
 446 * Description: nilfs_cpfile_delete_checkpoints() deletes the checkpoints in
 447 * the period from @start to @end, excluding @end itself. The checkpoints
 448 * which have been already deleted are ignored.
 449 *
 450 * Return: 0 on success, or one of the following negative error codes on
 451 * failure:
 452 * * %-EINVAL	- Invalid checkpoints.
 453 * * %-EIO	- I/O error (including metadata corruption).
 454 * * %-ENOMEM	- Insufficient memory available.
 455 */
 456int nilfs_cpfile_delete_checkpoints(struct inode *cpfile,
 457				    __u64 start,
 458				    __u64 end)
 459{
 460	struct buffer_head *header_bh, *cp_bh;
 461	struct nilfs_cpfile_header *header;
 462	struct nilfs_checkpoint *cp;
 463	size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
 464	__u64 cno;
 465	size_t offset;
 466	void *kaddr;
 467	unsigned long tnicps;
 468	int ret, ncps, nicps, nss, count, i;
 469
 470	if (unlikely(start == 0 || start > end)) {
 471		nilfs_err(cpfile->i_sb,
 472			  "cannot delete checkpoints: invalid range [%llu, %llu)",
 473			  (unsigned long long)start, (unsigned long long)end);
 474		return -EINVAL;
 475	}
 476
 477	down_write(&NILFS_MDT(cpfile)->mi_sem);
 478
 479	ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
 480	if (ret < 0)
 481		goto out_sem;
 482	tnicps = 0;
 483	nss = 0;
 484
 485	for (cno = start; cno < end; cno += ncps) {
 486		ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, end);
 487		ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
 488		if (ret < 0) {
 489			if (ret != -ENOENT)
 490				break;
 491			/* skip hole */
 492			ret = 0;
 493			continue;
 494		}
 495
 496		offset = nilfs_cpfile_checkpoint_offset(cpfile, cno, cp_bh);
 497		cp = kaddr = kmap_local_folio(cp_bh->b_folio, offset);
 498		nicps = 0;
 499		for (i = 0; i < ncps; i++, cp = (void *)cp + cpsz) {
 500			if (nilfs_checkpoint_snapshot(cp)) {
 501				nss++;
 502			} else if (!nilfs_checkpoint_invalid(cp)) {
 503				nilfs_checkpoint_set_invalid(cp);
 504				nicps++;
 505			}
 506		}
 507		kunmap_local(kaddr);
 508
 509		if (nicps <= 0) {
 510			brelse(cp_bh);
 511			continue;
 512		}
 513
 514		tnicps += nicps;
 515		mark_buffer_dirty(cp_bh);
 516		nilfs_mdt_mark_dirty(cpfile);
 517		if (nilfs_cpfile_is_in_first(cpfile, cno)) {
 518			brelse(cp_bh);
 519			continue;
 520		}
 521
 522		count = nilfs_cpfile_block_sub_valid_checkpoints(cpfile, cp_bh,
 523								 nicps);
 524		brelse(cp_bh);
 525		if (count)
 526			continue;
 527
 528		/* Delete the block if there are no more valid checkpoints */
 529		ret = nilfs_cpfile_delete_checkpoint_block(cpfile, cno);
 530		if (unlikely(ret)) {
 531			nilfs_err(cpfile->i_sb,
 532				  "error %d deleting checkpoint block", ret);
 533			break;
 534		}
 535	}
 536
 537	if (tnicps > 0) {
 538		header = kmap_local_folio(header_bh->b_folio, 0);
 539		le64_add_cpu(&header->ch_ncheckpoints, -(u64)tnicps);
 540		mark_buffer_dirty(header_bh);
 541		nilfs_mdt_mark_dirty(cpfile);
 542		kunmap_local(header);
 543	}
 544
 545	brelse(header_bh);
 546	if (nss > 0)
 547		ret = -EBUSY;
 548
 549 out_sem:
 550	up_write(&NILFS_MDT(cpfile)->mi_sem);
 551	return ret;
 552}
 553
 554static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile,
 555					      struct nilfs_checkpoint *cp,
 556					      struct nilfs_cpinfo *ci)
 557{
 558	ci->ci_flags = le32_to_cpu(cp->cp_flags);
 559	ci->ci_cno = le64_to_cpu(cp->cp_cno);
 560	ci->ci_create = le64_to_cpu(cp->cp_create);
 561	ci->ci_nblk_inc = le64_to_cpu(cp->cp_nblk_inc);
 562	ci->ci_inodes_count = le64_to_cpu(cp->cp_inodes_count);
 563	ci->ci_blocks_count = le64_to_cpu(cp->cp_blocks_count);
 564	ci->ci_next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);
 565}
 566
 567static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop,
 568					  void *buf, unsigned int cisz,
 569					  size_t nci)
 570{
 571	struct nilfs_checkpoint *cp;
 572	struct nilfs_cpinfo *ci = buf;
 573	struct buffer_head *bh;
 574	size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size;
 575	__u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop;
 576	size_t offset;
 577	void *kaddr;
 578	int n, ret;
 579	int ncps, i;
 580
 581	if (cno == 0)
 582		return -ENOENT; /* checkpoint number 0 is invalid */
 583	down_read(&NILFS_MDT(cpfile)->mi_sem);
 584
 585	for (n = 0; n < nci; cno += ncps) {
 586		ret = nilfs_cpfile_find_checkpoint_block(
 587			cpfile, cno, cur_cno - 1, &cno, &bh);
 588		if (ret < 0) {
 589			if (likely(ret == -ENOENT))
 590				break;
 591			goto out;
 592		}
 593		ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno);
 594
 595		offset = nilfs_cpfile_checkpoint_offset(cpfile, cno, bh);
 596		cp = kaddr = kmap_local_folio(bh->b_folio, offset);
 597		for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) {
 598			if (!nilfs_checkpoint_invalid(cp)) {
 599				nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp,
 600								  ci);
 601				ci = (void *)ci + cisz;
 602				n++;
 603			}
 604		}
 605		kunmap_local(kaddr);
 606		brelse(bh);
 607	}
 608
 609	ret = n;
 610	if (n > 0) {
 611		ci = (void *)ci - cisz;
 612		*cnop = ci->ci_cno + 1;
 613	}
 614
 615 out:
 616	up_read(&NILFS_MDT(cpfile)->mi_sem);
 617	return ret;
 618}
 619
 620static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop,
 621					  void *buf, unsigned int cisz,
 622					  size_t nci)
 623{
 624	struct buffer_head *bh;
 625	struct nilfs_cpfile_header *header;
 626	struct nilfs_checkpoint *cp;
 627	struct nilfs_cpinfo *ci = buf;
 628	__u64 curr = *cnop, next;
 629	unsigned long curr_blkoff, next_blkoff;
 630	size_t offset;
 631	int n = 0, ret;
 632
 633	down_read(&NILFS_MDT(cpfile)->mi_sem);
 634
 635	if (curr == 0) {
 636		ret = nilfs_cpfile_get_header_block(cpfile, &bh);
 637		if (ret < 0)
 638			goto out;
 639		header = kmap_local_folio(bh->b_folio, 0);
 640		curr = le64_to_cpu(header->ch_snapshot_list.ssl_next);
 641		kunmap_local(header);
 642		brelse(bh);
 643		if (curr == 0) {
 644			ret = 0;
 645			goto out;
 646		}
 647	} else if (unlikely(curr == ~(__u64)0)) {
 648		ret = 0;
 649		goto out;
 650	}
 651
 652	curr_blkoff = nilfs_cpfile_get_blkoff(cpfile, curr);
 653	ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr, 0, &bh);
 654	if (unlikely(ret < 0)) {
 655		if (ret == -ENOENT)
 656			ret = 0; /* No snapshots (started from a hole block) */
 657		goto out;
 658	}
 659	offset = nilfs_cpfile_checkpoint_offset(cpfile, curr, bh);
 660	cp = kmap_local_folio(bh->b_folio, offset);
 661	while (n < nci) {
 662		curr = ~(__u64)0; /* Terminator */
 663		if (unlikely(nilfs_checkpoint_invalid(cp) ||
 664			     !nilfs_checkpoint_snapshot(cp)))
 665			break;
 666		nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, ci);
 667		ci = (void *)ci + cisz;
 668		n++;
 669		next = le64_to_cpu(cp->cp_snapshot_list.ssl_next);
 670		if (next == 0)
 671			break; /* reach end of the snapshot list */
 672
 673		kunmap_local(cp);
 674		next_blkoff = nilfs_cpfile_get_blkoff(cpfile, next);
 675		if (curr_blkoff != next_blkoff) {
 676			brelse(bh);
 677			ret = nilfs_cpfile_get_checkpoint_block(cpfile, next,
 678								0, &bh);
 679			if (unlikely(ret < 0)) {
 680				WARN_ON(ret == -ENOENT);
 681				goto out;
 682			}
 683		}
 684		offset = nilfs_cpfile_checkpoint_offset(cpfile, next, bh);
 685		cp = kmap_local_folio(bh->b_folio, offset);
 686		curr = next;
 687		curr_blkoff = next_blkoff;
 688	}
 689	kunmap_local(cp);
 690	brelse(bh);
 691	*cnop = curr;
 692	ret = n;
 693
 694 out:
 695	up_read(&NILFS_MDT(cpfile)->mi_sem);
 696	return ret;
 697}
 698
 699/**
 700 * nilfs_cpfile_get_cpinfo - get information on checkpoints
 701 * @cpfile: checkpoint file inode
 702 * @cnop:   place to pass a starting checkpoint number and receive a
 703 *          checkpoint number to continue the search
 704 * @mode:   mode of checkpoints that the caller wants to retrieve
 705 * @buf:    buffer for storing checkpoints' information
 706 * @cisz:   byte size of one checkpoint info item in array
 707 * @nci:    number of checkpoint info items to retrieve
 708 *
 709 * nilfs_cpfile_get_cpinfo() searches for checkpoints in @mode state
 710 * starting from the checkpoint number stored in @cnop, and stores
 711 * information about found checkpoints in @buf.
 712 * The buffer pointed to by @buf must be large enough to store information
 713 * for @nci checkpoints.  If at least one checkpoint information is
 714 * successfully retrieved, @cnop is updated to point to the checkpoint
 715 * number to continue searching.
 716 *
 717 * Return: Count of checkpoint info items stored in the output buffer on
 718 * success, or one of the following negative error codes on failure:
 719 * * %-EINVAL	- Invalid checkpoint mode.
 720 * * %-ENOMEM	- Insufficient memory available.
 721 * * %-EIO	- I/O error (including metadata corruption).
 722 * * %-ENOENT	- Invalid checkpoint number specified.
 723 */
 724
 725ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode,
 726				void *buf, unsigned int cisz, size_t nci)
 727{
 728	switch (mode) {
 729	case NILFS_CHECKPOINT:
 730		return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, buf, cisz, nci);
 731	case NILFS_SNAPSHOT:
 732		return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, buf, cisz, nci);
 733	default:
 734		return -EINVAL;
 735	}
 736}
 737
 738/**
 739 * nilfs_cpfile_delete_checkpoint - delete a checkpoint
 740 * @cpfile: checkpoint file inode
 741 * @cno:    checkpoint number to delete
 742 *
 743 * Return: 0 on success, or one of the following negative error codes on
 744 * failure:
 745 * * %-EBUSY	- Checkpoint in use (snapshot specified).
 746 * * %-EIO	- I/O error (including metadata corruption).
 747 * * %-ENOENT	- No valid checkpoint found.
 748 * * %-ENOMEM	- Insufficient memory available.
 749 */
 750int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno)
 751{
 752	struct nilfs_cpinfo ci;
 753	__u64 tcno = cno;
 754	ssize_t nci;
 755
 756	nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, sizeof(ci), 1);
 757	if (nci < 0)
 758		return nci;
 759	else if (nci == 0 || ci.ci_cno != cno)
 760		return -ENOENT;
 761	else if (nilfs_cpinfo_snapshot(&ci))
 762		return -EBUSY;
 763
 764	return nilfs_cpfile_delete_checkpoints(cpfile, cno, cno + 1);
 765}
 766
 767static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno)
 768{
 769	struct buffer_head *header_bh, *curr_bh, *prev_bh, *cp_bh;
 770	struct nilfs_cpfile_header *header;
 771	struct nilfs_checkpoint *cp;
 772	struct nilfs_snapshot_list *list;
 773	__u64 curr, prev;
 774	unsigned long curr_blkoff, prev_blkoff;
 775	size_t offset, curr_list_offset, prev_list_offset;
 776	int ret;
 777
 778	if (cno == 0)
 779		return -ENOENT; /* checkpoint number 0 is invalid */
 780	down_write(&NILFS_MDT(cpfile)->mi_sem);
 781
 782	ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
 783	if (unlikely(ret < 0))
 784		goto out_sem;
 785
 786	ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
 787	if (ret < 0)
 788		goto out_header;
 789
 790	offset = nilfs_cpfile_checkpoint_offset(cpfile, cno, cp_bh);
 791	cp = kmap_local_folio(cp_bh->b_folio, offset);
 792	if (nilfs_checkpoint_invalid(cp)) {
 793		ret = -ENOENT;
 794		kunmap_local(cp);
 795		goto out_cp;
 796	}
 797	if (nilfs_checkpoint_snapshot(cp)) {
 798		ret = 0;
 799		kunmap_local(cp);
 800		goto out_cp;
 801	}
 802	kunmap_local(cp);
 803
 804	/*
 805	 * Find the last snapshot before the checkpoint being changed to
 806	 * snapshot mode by going backwards through the snapshot list.
 807	 * Set "prev" to its checkpoint number, or 0 if not found.
 808	 */
 809	header = kmap_local_folio(header_bh->b_folio, 0);
 810	list = &header->ch_snapshot_list;
 811	curr_bh = header_bh;
 812	get_bh(curr_bh);
 813	curr = 0;
 814	curr_blkoff = 0;
 815	curr_list_offset = nilfs_cpfile_ch_snapshot_list_offset();
 816	prev = le64_to_cpu(list->ssl_prev);
 817	while (prev > cno) {
 818		prev_blkoff = nilfs_cpfile_get_blkoff(cpfile, prev);
 819		curr = prev;
 820		kunmap_local(list);
 821		if (curr_blkoff != prev_blkoff) {
 822			brelse(curr_bh);
 823			ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr,
 824								0, &curr_bh);
 825			if (unlikely(ret < 0))
 826				goto out_cp;
 827		}
 828		curr_list_offset = nilfs_cpfile_cp_snapshot_list_offset(
 829			cpfile, curr, curr_bh);
 830		list = kmap_local_folio(curr_bh->b_folio, curr_list_offset);
 831		curr_blkoff = prev_blkoff;
 832		prev = le64_to_cpu(list->ssl_prev);
 833	}
 834	kunmap_local(list);
 835
 836	if (prev != 0) {
 837		ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0,
 838							&prev_bh);
 839		if (ret < 0)
 840			goto out_curr;
 841
 842		prev_list_offset = nilfs_cpfile_cp_snapshot_list_offset(
 843			cpfile, prev, prev_bh);
 844	} else {
 845		prev_bh = header_bh;
 846		get_bh(prev_bh);
 847		prev_list_offset = nilfs_cpfile_ch_snapshot_list_offset();
 848	}
 849
 850	/* Update the list entry for the next snapshot */
 851	list = kmap_local_folio(curr_bh->b_folio, curr_list_offset);
 852	list->ssl_prev = cpu_to_le64(cno);
 853	kunmap_local(list);
 854
 855	/* Update the checkpoint being changed to a snapshot */
 856	offset = nilfs_cpfile_checkpoint_offset(cpfile, cno, cp_bh);
 857	cp = kmap_local_folio(cp_bh->b_folio, offset);
 858	cp->cp_snapshot_list.ssl_next = cpu_to_le64(curr);
 859	cp->cp_snapshot_list.ssl_prev = cpu_to_le64(prev);
 860	nilfs_checkpoint_set_snapshot(cp);
 861	kunmap_local(cp);
 862
 863	/* Update the list entry for the previous snapshot */
 864	list = kmap_local_folio(prev_bh->b_folio, prev_list_offset);
 865	list->ssl_next = cpu_to_le64(cno);
 866	kunmap_local(list);
 867
 868	/* Update the statistics in the header */
 869	header = kmap_local_folio(header_bh->b_folio, 0);
 870	le64_add_cpu(&header->ch_nsnapshots, 1);
 871	kunmap_local(header);
 872
 873	mark_buffer_dirty(prev_bh);
 874	mark_buffer_dirty(curr_bh);
 875	mark_buffer_dirty(cp_bh);
 876	mark_buffer_dirty(header_bh);
 877	nilfs_mdt_mark_dirty(cpfile);
 878
 879	brelse(prev_bh);
 880
 881 out_curr:
 882	brelse(curr_bh);
 883
 884 out_cp:
 885	brelse(cp_bh);
 886
 887 out_header:
 888	brelse(header_bh);
 889
 890 out_sem:
 891	up_write(&NILFS_MDT(cpfile)->mi_sem);
 892	return ret;
 893}
 894
 895static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno)
 896{
 897	struct buffer_head *header_bh, *next_bh, *prev_bh, *cp_bh;
 898	struct nilfs_cpfile_header *header;
 899	struct nilfs_checkpoint *cp;
 900	struct nilfs_snapshot_list *list;
 901	__u64 next, prev;
 902	size_t offset, next_list_offset, prev_list_offset;
 903	int ret;
 904
 905	if (cno == 0)
 906		return -ENOENT; /* checkpoint number 0 is invalid */
 907	down_write(&NILFS_MDT(cpfile)->mi_sem);
 908
 909	ret = nilfs_cpfile_get_header_block(cpfile, &header_bh);
 910	if (unlikely(ret < 0))
 911		goto out_sem;
 912
 913	ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh);
 914	if (ret < 0)
 915		goto out_header;
 916
 917	offset = nilfs_cpfile_checkpoint_offset(cpfile, cno, cp_bh);
 918	cp = kmap_local_folio(cp_bh->b_folio, offset);
 919	if (nilfs_checkpoint_invalid(cp)) {
 920		ret = -ENOENT;
 921		kunmap_local(cp);
 922		goto out_cp;
 923	}
 924	if (!nilfs_checkpoint_snapshot(cp)) {
 925		ret = 0;
 926		kunmap_local(cp);
 927		goto out_cp;
 928	}
 929
 930	list = &cp->cp_snapshot_list;
 931	next = le64_to_cpu(list->ssl_next);
 932	prev = le64_to_cpu(list->ssl_prev);
 933	kunmap_local(cp);
 934
 935	if (next != 0) {
 936		ret = nilfs_cpfile_get_checkpoint_block(cpfile, next, 0,
 937							&next_bh);
 938		if (ret < 0)
 939			goto out_cp;
 940
 941		next_list_offset = nilfs_cpfile_cp_snapshot_list_offset(
 942			cpfile, next, next_bh);
 943	} else {
 944		next_bh = header_bh;
 945		get_bh(next_bh);
 946		next_list_offset = nilfs_cpfile_ch_snapshot_list_offset();
 947	}
 948	if (prev != 0) {
 949		ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0,
 950							&prev_bh);
 951		if (ret < 0)
 952			goto out_next;
 953
 954		prev_list_offset = nilfs_cpfile_cp_snapshot_list_offset(
 955			cpfile, prev, prev_bh);
 956	} else {
 957		prev_bh = header_bh;
 958		get_bh(prev_bh);
 959		prev_list_offset = nilfs_cpfile_ch_snapshot_list_offset();
 960	}
 961
 962	/* Update the list entry for the next snapshot */
 963	list = kmap_local_folio(next_bh->b_folio, next_list_offset);
 964	list->ssl_prev = cpu_to_le64(prev);
 965	kunmap_local(list);
 966
 967	/* Update the list entry for the previous snapshot */
 968	list = kmap_local_folio(prev_bh->b_folio, prev_list_offset);
 969	list->ssl_next = cpu_to_le64(next);
 970	kunmap_local(list);
 971
 972	/* Update the snapshot being changed back to a plain checkpoint */
 973	cp = kmap_local_folio(cp_bh->b_folio, offset);
 974	cp->cp_snapshot_list.ssl_next = cpu_to_le64(0);
 975	cp->cp_snapshot_list.ssl_prev = cpu_to_le64(0);
 976	nilfs_checkpoint_clear_snapshot(cp);
 977	kunmap_local(cp);
 978
 979	/* Update the statistics in the header */
 980	header = kmap_local_folio(header_bh->b_folio, 0);
 981	le64_add_cpu(&header->ch_nsnapshots, -1);
 982	kunmap_local(header);
 983
 984	mark_buffer_dirty(next_bh);
 985	mark_buffer_dirty(prev_bh);
 986	mark_buffer_dirty(cp_bh);
 987	mark_buffer_dirty(header_bh);
 988	nilfs_mdt_mark_dirty(cpfile);
 989
 990	brelse(prev_bh);
 991
 992 out_next:
 993	brelse(next_bh);
 994
 995 out_cp:
 996	brelse(cp_bh);
 997
 998 out_header:
 999	brelse(header_bh);
1000
1001 out_sem:
1002	up_write(&NILFS_MDT(cpfile)->mi_sem);
1003	return ret;
1004}
1005
1006/**
1007 * nilfs_cpfile_is_snapshot - determine if checkpoint is a snapshot
1008 * @cpfile: inode of checkpoint file
1009 * @cno:    checkpoint number
1010 *
1011 * Return: 1 if the checkpoint specified by @cno is a snapshot, 0 if not, or
1012 * one of the following negative error codes on failure:
1013 * * %-EIO	- I/O error (including metadata corruption).
1014 * * %-ENOENT	- No such checkpoint.
1015 * * %-ENOMEM	- Insufficient memory available.
1016 */
1017int nilfs_cpfile_is_snapshot(struct inode *cpfile, __u64 cno)
1018{
1019	struct buffer_head *bh;
1020	struct nilfs_checkpoint *cp;
1021	size_t offset;
1022	int ret;
1023
1024	/*
1025	 * CP number is invalid if it's zero or larger than the
1026	 * largest existing one.
1027	 */
1028	if (cno == 0 || cno >= nilfs_mdt_cno(cpfile))
1029		return -ENOENT;
1030	down_read(&NILFS_MDT(cpfile)->mi_sem);
1031
1032	ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh);
1033	if (ret < 0)
1034		goto out;
1035
1036	offset = nilfs_cpfile_checkpoint_offset(cpfile, cno, bh);
1037	cp = kmap_local_folio(bh->b_folio, offset);
1038	if (nilfs_checkpoint_invalid(cp))
1039		ret = -ENOENT;
1040	else
1041		ret = nilfs_checkpoint_snapshot(cp);
1042	kunmap_local(cp);
1043	brelse(bh);
1044
1045 out:
1046	up_read(&NILFS_MDT(cpfile)->mi_sem);
1047	return ret;
1048}
1049
1050/**
1051 * nilfs_cpfile_change_cpmode - change checkpoint mode
1052 * @cpfile: inode of checkpoint file
1053 * @cno: checkpoint number
1054 * @mode: mode of checkpoint
1055 *
1056 * Description: nilfs_change_cpmode() changes the mode of the checkpoint
1057 * specified by @cno. The mode @mode is NILFS_CHECKPOINT or NILFS_SNAPSHOT.
1058 *
1059 * Return: 0 on success, or one of the following negative error codes on
1060 * failure:
1061 * * %-EIO	- I/O error (including metadata corruption).
1062 * * %-ENOENT	- No such checkpoint.
1063 * * %-ENOMEM	- Insufficient memory available.
1064 */
1065int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode)
1066{
1067	int ret;
1068
1069	switch (mode) {
1070	case NILFS_CHECKPOINT:
1071		if (nilfs_checkpoint_is_mounted(cpfile->i_sb, cno))
1072			/*
1073			 * Current implementation does not have to protect
1074			 * plain read-only mounts since they are exclusive
1075			 * with a read/write mount and are protected from the
1076			 * cleaner.
1077			 */
1078			ret = -EBUSY;
1079		else
1080			ret = nilfs_cpfile_clear_snapshot(cpfile, cno);
1081		return ret;
1082	case NILFS_SNAPSHOT:
1083		return nilfs_cpfile_set_snapshot(cpfile, cno);
1084	default:
1085		return -EINVAL;
1086	}
1087}
1088
1089/**
1090 * nilfs_cpfile_get_stat - get checkpoint statistics
1091 * @cpfile: inode of checkpoint file
1092 * @cpstat: pointer to a structure of checkpoint statistics
1093 *
1094 * Description: nilfs_cpfile_get_stat() returns information about checkpoints.
1095 * The checkpoint statistics are stored in the location pointed to by @cpstat.
1096 *
1097 * Return: 0 on success, or one of the following negative error codes on
1098 * failure:
1099 * * %-EIO	- I/O error (including metadata corruption).
1100 * * %-ENOMEM	- Insufficient memory available.
1101 */
1102int nilfs_cpfile_get_stat(struct inode *cpfile, struct nilfs_cpstat *cpstat)
1103{
1104	struct buffer_head *bh;
1105	struct nilfs_cpfile_header *header;
1106	int ret;
1107
1108	down_read(&NILFS_MDT(cpfile)->mi_sem);
1109
1110	ret = nilfs_cpfile_get_header_block(cpfile, &bh);
1111	if (ret < 0)
1112		goto out_sem;
1113	header = kmap_local_folio(bh->b_folio, 0);
1114	cpstat->cs_cno = nilfs_mdt_cno(cpfile);
1115	cpstat->cs_ncps = le64_to_cpu(header->ch_ncheckpoints);
1116	cpstat->cs_nsss = le64_to_cpu(header->ch_nsnapshots);
1117	kunmap_local(header);
1118	brelse(bh);
1119
1120 out_sem:
1121	up_read(&NILFS_MDT(cpfile)->mi_sem);
1122	return ret;
1123}
1124
1125/**
1126 * nilfs_cpfile_read - read or get cpfile inode
1127 * @sb: super block instance
1128 * @cpsize: size of a checkpoint entry
1129 * @raw_inode: on-disk cpfile inode
1130 * @inodep: buffer to store the inode
1131 *
1132 * Return: 0 on success, or a negative error code on failure.
1133 */
1134int nilfs_cpfile_read(struct super_block *sb, size_t cpsize,
1135		      struct nilfs_inode *raw_inode, struct inode **inodep)
1136{
1137	struct inode *cpfile;
1138	int err;
1139
1140	if (cpsize > sb->s_blocksize) {
1141		nilfs_err(sb, "too large checkpoint size: %zu bytes", cpsize);
1142		return -EINVAL;
1143	} else if (cpsize < NILFS_MIN_CHECKPOINT_SIZE) {
1144		nilfs_err(sb, "too small checkpoint size: %zu bytes", cpsize);
1145		return -EINVAL;
1146	}
1147
1148	cpfile = nilfs_iget_locked(sb, NULL, NILFS_CPFILE_INO);
1149	if (unlikely(!cpfile))
1150		return -ENOMEM;
1151	if (!(inode_state_read_once(cpfile) & I_NEW))
1152		goto out;
1153
1154	err = nilfs_mdt_init(cpfile, NILFS_MDT_GFP, 0);
1155	if (err)
1156		goto failed;
1157
1158	nilfs_mdt_set_entry_size(cpfile, cpsize,
1159				 sizeof(struct nilfs_cpfile_header));
1160
1161	err = nilfs_read_inode_common(cpfile, raw_inode);
1162	if (err)
1163		goto failed;
1164
1165	unlock_new_inode(cpfile);
1166 out:
1167	*inodep = cpfile;
1168	return 0;
1169 failed:
1170	iget_failed(cpfile);
1171	return err;
1172}
~/ Read-only file preview.