1ae98043fSRyusuke Konishi // SPDX-License-Identifier: GPL-2.0+ 229619809SKoji Sato /* 394ee1d91SRyusuke Konishi * NILFS checkpoint file. 429619809SKoji Sato * 529619809SKoji Sato * Copyright (C) 2006-2008 Nippon Telegraph and Telephone Corporation. 629619809SKoji Sato * 74b420ab4SRyusuke Konishi * Written by Koji Sato. 829619809SKoji Sato */ 929619809SKoji Sato 1029619809SKoji Sato #include <linux/kernel.h> 1129619809SKoji Sato #include <linux/fs.h> 1229619809SKoji Sato #include <linux/string.h> 1329619809SKoji Sato #include <linux/buffer_head.h> 1429619809SKoji Sato #include <linux/errno.h> 1529619809SKoji Sato #include "mdt.h" 1629619809SKoji Sato #include "cpfile.h" 1729619809SKoji Sato 1829619809SKoji Sato 1929619809SKoji Sato static inline unsigned long 2029619809SKoji Sato nilfs_cpfile_checkpoints_per_block(const struct inode *cpfile) 2129619809SKoji Sato { 2229619809SKoji Sato return NILFS_MDT(cpfile)->mi_entries_per_block; 2329619809SKoji Sato } 2429619809SKoji Sato 2529619809SKoji Sato /* block number from the beginning of the file */ 2629619809SKoji Sato static unsigned long 2729619809SKoji Sato nilfs_cpfile_get_blkoff(const struct inode *cpfile, __u64 cno) 2829619809SKoji Sato { 291f5abe7eSRyusuke Konishi __u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1; 304ad364caSRyusuke Konishi 31adc2c8d0SThorsten Blum tcno = div64_ul(tcno, nilfs_cpfile_checkpoints_per_block(cpfile)); 3229619809SKoji Sato return (unsigned long)tcno; 3329619809SKoji Sato } 3429619809SKoji Sato 3529619809SKoji Sato /* offset in block */ 3629619809SKoji Sato static unsigned long 3729619809SKoji Sato nilfs_cpfile_get_offset(const struct inode *cpfile, __u64 cno) 3829619809SKoji Sato { 3929619809SKoji Sato __u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1; 404ad364caSRyusuke Konishi 4129619809SKoji Sato return do_div(tcno, nilfs_cpfile_checkpoints_per_block(cpfile)); 4229619809SKoji Sato } 4329619809SKoji Sato 4453a2c3bdSRyusuke Konishi static __u64 nilfs_cpfile_first_checkpoint_in_block(const struct inode *cpfile, 4553a2c3bdSRyusuke Konishi unsigned long blkoff) 4653a2c3bdSRyusuke Konishi { 4753a2c3bdSRyusuke Konishi return (__u64)nilfs_cpfile_checkpoints_per_block(cpfile) * blkoff 4853a2c3bdSRyusuke Konishi + 1 - NILFS_MDT(cpfile)->mi_first_entry_offset; 4953a2c3bdSRyusuke Konishi } 5053a2c3bdSRyusuke Konishi 5129619809SKoji Sato static unsigned long 5229619809SKoji Sato nilfs_cpfile_checkpoints_in_block(const struct inode *cpfile, 5329619809SKoji Sato __u64 curr, 5429619809SKoji Sato __u64 max) 5529619809SKoji Sato { 5629619809SKoji Sato return min_t(__u64, 5729619809SKoji Sato nilfs_cpfile_checkpoints_per_block(cpfile) - 5829619809SKoji Sato nilfs_cpfile_get_offset(cpfile, curr), 5929619809SKoji Sato max - curr); 6029619809SKoji Sato } 6129619809SKoji Sato 6229619809SKoji Sato static inline int nilfs_cpfile_is_in_first(const struct inode *cpfile, 6329619809SKoji Sato __u64 cno) 6429619809SKoji Sato { 6529619809SKoji Sato return nilfs_cpfile_get_blkoff(cpfile, cno) == 0; 6629619809SKoji Sato } 6729619809SKoji Sato 6829619809SKoji Sato static unsigned int 6929619809SKoji Sato nilfs_cpfile_block_add_valid_checkpoints(const struct inode *cpfile, 7029619809SKoji Sato struct buffer_head *bh, 7129619809SKoji Sato void *kaddr, 7229619809SKoji Sato unsigned int n) 7329619809SKoji Sato { 7429619809SKoji Sato struct nilfs_checkpoint *cp = kaddr + bh_offset(bh); 7529619809SKoji Sato unsigned int count; 7629619809SKoji Sato 7729619809SKoji Sato count = le32_to_cpu(cp->cp_checkpoints_count) + n; 7829619809SKoji Sato cp->cp_checkpoints_count = cpu_to_le32(count); 7929619809SKoji Sato return count; 8029619809SKoji Sato } 8129619809SKoji Sato 8229619809SKoji Sato static unsigned int 8329619809SKoji Sato nilfs_cpfile_block_sub_valid_checkpoints(const struct inode *cpfile, 8429619809SKoji Sato struct buffer_head *bh, 8529619809SKoji Sato void *kaddr, 8629619809SKoji Sato unsigned int n) 8729619809SKoji Sato { 8829619809SKoji Sato struct nilfs_checkpoint *cp = kaddr + bh_offset(bh); 8929619809SKoji Sato unsigned int count; 9029619809SKoji Sato 911f5abe7eSRyusuke Konishi WARN_ON(le32_to_cpu(cp->cp_checkpoints_count) < n); 9229619809SKoji Sato count = le32_to_cpu(cp->cp_checkpoints_count) - n; 9329619809SKoji Sato cp->cp_checkpoints_count = cpu_to_le32(count); 9429619809SKoji Sato return count; 9529619809SKoji Sato } 9629619809SKoji Sato 9729619809SKoji Sato static inline struct nilfs_cpfile_header * 9829619809SKoji Sato nilfs_cpfile_block_get_header(const struct inode *cpfile, 9929619809SKoji Sato struct buffer_head *bh, 10029619809SKoji Sato void *kaddr) 10129619809SKoji Sato { 10229619809SKoji Sato return kaddr + bh_offset(bh); 10329619809SKoji Sato } 10429619809SKoji Sato 10529619809SKoji Sato static struct nilfs_checkpoint * 10629619809SKoji Sato nilfs_cpfile_block_get_checkpoint(const struct inode *cpfile, __u64 cno, 10729619809SKoji Sato struct buffer_head *bh, 10829619809SKoji Sato void *kaddr) 10929619809SKoji Sato { 11029619809SKoji Sato return kaddr + bh_offset(bh) + nilfs_cpfile_get_offset(cpfile, cno) * 11129619809SKoji Sato NILFS_MDT(cpfile)->mi_entry_size; 11229619809SKoji Sato } 11329619809SKoji Sato 11429619809SKoji Sato static void nilfs_cpfile_block_init(struct inode *cpfile, 11529619809SKoji Sato struct buffer_head *bh, 11629619809SKoji Sato void *kaddr) 11729619809SKoji Sato { 11829619809SKoji Sato struct nilfs_checkpoint *cp = kaddr + bh_offset(bh); 11929619809SKoji Sato size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size; 12029619809SKoji Sato int n = nilfs_cpfile_checkpoints_per_block(cpfile); 12129619809SKoji Sato 12229619809SKoji Sato while (n-- > 0) { 12329619809SKoji Sato nilfs_checkpoint_set_invalid(cp); 12429619809SKoji Sato cp = (void *)cp + cpsz; 12529619809SKoji Sato } 12629619809SKoji Sato } 12729619809SKoji Sato 128*d07d8ba4SRyusuke Konishi static int nilfs_cpfile_get_header_block(struct inode *cpfile, 12929619809SKoji Sato struct buffer_head **bhp) 13029619809SKoji Sato { 131*d07d8ba4SRyusuke Konishi int err = nilfs_mdt_get_block(cpfile, 0, 0, NULL, bhp); 132*d07d8ba4SRyusuke Konishi 133*d07d8ba4SRyusuke Konishi if (unlikely(err == -ENOENT)) { 134*d07d8ba4SRyusuke Konishi nilfs_error(cpfile->i_sb, 135*d07d8ba4SRyusuke Konishi "missing header block in checkpoint metadata"); 136*d07d8ba4SRyusuke Konishi err = -EIO; 137*d07d8ba4SRyusuke Konishi } 138*d07d8ba4SRyusuke Konishi return err; 13929619809SKoji Sato } 14029619809SKoji Sato 14129619809SKoji Sato static inline int nilfs_cpfile_get_checkpoint_block(struct inode *cpfile, 14229619809SKoji Sato __u64 cno, 14329619809SKoji Sato int create, 14429619809SKoji Sato struct buffer_head **bhp) 14529619809SKoji Sato { 14629619809SKoji Sato return nilfs_mdt_get_block(cpfile, 14729619809SKoji Sato nilfs_cpfile_get_blkoff(cpfile, cno), 14829619809SKoji Sato create, nilfs_cpfile_block_init, bhp); 14929619809SKoji Sato } 15029619809SKoji Sato 15153a2c3bdSRyusuke Konishi /** 15253a2c3bdSRyusuke Konishi * nilfs_cpfile_find_checkpoint_block - find and get a buffer on cpfile 15353a2c3bdSRyusuke Konishi * @cpfile: inode of cpfile 15453a2c3bdSRyusuke Konishi * @start_cno: start checkpoint number (inclusive) 15553a2c3bdSRyusuke Konishi * @end_cno: end checkpoint number (inclusive) 15653a2c3bdSRyusuke Konishi * @cnop: place to store the next checkpoint number 15753a2c3bdSRyusuke Konishi * @bhp: place to store a pointer to buffer_head struct 15853a2c3bdSRyusuke Konishi * 15953a2c3bdSRyusuke Konishi * Return Value: On success, it returns 0. On error, the following negative 16053a2c3bdSRyusuke Konishi * error code is returned. 16153a2c3bdSRyusuke Konishi * 16253a2c3bdSRyusuke Konishi * %-ENOMEM - Insufficient memory available. 16353a2c3bdSRyusuke Konishi * 16453a2c3bdSRyusuke Konishi * %-EIO - I/O error 16553a2c3bdSRyusuke Konishi * 16653a2c3bdSRyusuke Konishi * %-ENOENT - no block exists in the range. 16753a2c3bdSRyusuke Konishi */ 16853a2c3bdSRyusuke Konishi static int nilfs_cpfile_find_checkpoint_block(struct inode *cpfile, 16953a2c3bdSRyusuke Konishi __u64 start_cno, __u64 end_cno, 17053a2c3bdSRyusuke Konishi __u64 *cnop, 17153a2c3bdSRyusuke Konishi struct buffer_head **bhp) 17253a2c3bdSRyusuke Konishi { 17353a2c3bdSRyusuke Konishi unsigned long start, end, blkoff; 17453a2c3bdSRyusuke Konishi int ret; 17553a2c3bdSRyusuke Konishi 17653a2c3bdSRyusuke Konishi if (unlikely(start_cno > end_cno)) 17753a2c3bdSRyusuke Konishi return -ENOENT; 17853a2c3bdSRyusuke Konishi 17953a2c3bdSRyusuke Konishi start = nilfs_cpfile_get_blkoff(cpfile, start_cno); 18053a2c3bdSRyusuke Konishi end = nilfs_cpfile_get_blkoff(cpfile, end_cno); 18153a2c3bdSRyusuke Konishi 18253a2c3bdSRyusuke Konishi ret = nilfs_mdt_find_block(cpfile, start, end, &blkoff, bhp); 18353a2c3bdSRyusuke Konishi if (!ret) 18453a2c3bdSRyusuke Konishi *cnop = (blkoff == start) ? start_cno : 18553a2c3bdSRyusuke Konishi nilfs_cpfile_first_checkpoint_in_block(cpfile, blkoff); 18653a2c3bdSRyusuke Konishi return ret; 18753a2c3bdSRyusuke Konishi } 18853a2c3bdSRyusuke Konishi 18929619809SKoji Sato static inline int nilfs_cpfile_delete_checkpoint_block(struct inode *cpfile, 19029619809SKoji Sato __u64 cno) 19129619809SKoji Sato { 19229619809SKoji Sato return nilfs_mdt_delete_block(cpfile, 19329619809SKoji Sato nilfs_cpfile_get_blkoff(cpfile, cno)); 19429619809SKoji Sato } 19529619809SKoji Sato 19629619809SKoji Sato /** 1971244a6d7SRyusuke Konishi * nilfs_cpfile_read_checkpoint - read a checkpoint entry in cpfile 1981244a6d7SRyusuke Konishi * @cpfile: checkpoint file inode 1991244a6d7SRyusuke Konishi * @cno: number of checkpoint entry to read 2001244a6d7SRyusuke Konishi * @root: nilfs root object 2011244a6d7SRyusuke Konishi * @ifile: ifile's inode to read and attach to @root 2021244a6d7SRyusuke Konishi * 2031244a6d7SRyusuke Konishi * This function imports checkpoint information from the checkpoint file and 2041244a6d7SRyusuke Konishi * stores it to the inode file given by @ifile and the nilfs root object 2051244a6d7SRyusuke Konishi * given by @root. 2061244a6d7SRyusuke Konishi * 2071244a6d7SRyusuke Konishi * Return: 0 on success, or the following negative error code on failure. 2081244a6d7SRyusuke Konishi * * %-EINVAL - Invalid checkpoint. 2091244a6d7SRyusuke Konishi * * %-ENOMEM - Insufficient memory available. 2101244a6d7SRyusuke Konishi * * %-EIO - I/O error (including metadata corruption). 2111244a6d7SRyusuke Konishi */ 2121244a6d7SRyusuke Konishi int nilfs_cpfile_read_checkpoint(struct inode *cpfile, __u64 cno, 2131244a6d7SRyusuke Konishi struct nilfs_root *root, struct inode *ifile) 2141244a6d7SRyusuke Konishi { 2151244a6d7SRyusuke Konishi struct buffer_head *cp_bh; 2161244a6d7SRyusuke Konishi struct nilfs_checkpoint *cp; 2171244a6d7SRyusuke Konishi void *kaddr; 2181244a6d7SRyusuke Konishi int ret; 2191244a6d7SRyusuke Konishi 2201244a6d7SRyusuke Konishi if (cno < 1 || cno > nilfs_mdt_cno(cpfile)) 2211244a6d7SRyusuke Konishi return -EINVAL; 2221244a6d7SRyusuke Konishi 2231244a6d7SRyusuke Konishi down_read(&NILFS_MDT(cpfile)->mi_sem); 2241244a6d7SRyusuke Konishi ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); 2251244a6d7SRyusuke Konishi if (unlikely(ret < 0)) { 2261244a6d7SRyusuke Konishi if (ret == -ENOENT) 2271244a6d7SRyusuke Konishi ret = -EINVAL; 2281244a6d7SRyusuke Konishi goto out_sem; 2291244a6d7SRyusuke Konishi } 2301244a6d7SRyusuke Konishi 2311244a6d7SRyusuke Konishi kaddr = kmap_local_page(cp_bh->b_page); 2321244a6d7SRyusuke Konishi cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr); 2331244a6d7SRyusuke Konishi if (nilfs_checkpoint_invalid(cp)) { 2341244a6d7SRyusuke Konishi ret = -EINVAL; 2351244a6d7SRyusuke Konishi goto put_cp; 2361244a6d7SRyusuke Konishi } 2371244a6d7SRyusuke Konishi 2381244a6d7SRyusuke Konishi ret = nilfs_read_inode_common(ifile, &cp->cp_ifile_inode); 2391244a6d7SRyusuke Konishi if (unlikely(ret)) { 2401244a6d7SRyusuke Konishi /* 2411244a6d7SRyusuke Konishi * Since this inode is on a checkpoint entry, treat errors 2421244a6d7SRyusuke Konishi * as metadata corruption. 2431244a6d7SRyusuke Konishi */ 2441244a6d7SRyusuke Konishi nilfs_err(cpfile->i_sb, 2451244a6d7SRyusuke Konishi "ifile inode (checkpoint number=%llu) corrupted", 2461244a6d7SRyusuke Konishi (unsigned long long)cno); 2471244a6d7SRyusuke Konishi ret = -EIO; 2481244a6d7SRyusuke Konishi goto put_cp; 2491244a6d7SRyusuke Konishi } 2501244a6d7SRyusuke Konishi 2511244a6d7SRyusuke Konishi /* Configure the nilfs root object */ 2521244a6d7SRyusuke Konishi atomic64_set(&root->inodes_count, le64_to_cpu(cp->cp_inodes_count)); 2531244a6d7SRyusuke Konishi atomic64_set(&root->blocks_count, le64_to_cpu(cp->cp_blocks_count)); 2541244a6d7SRyusuke Konishi root->ifile = ifile; 2551244a6d7SRyusuke Konishi 2561244a6d7SRyusuke Konishi put_cp: 2571244a6d7SRyusuke Konishi kunmap_local(kaddr); 2581244a6d7SRyusuke Konishi brelse(cp_bh); 2591244a6d7SRyusuke Konishi out_sem: 2601244a6d7SRyusuke Konishi up_read(&NILFS_MDT(cpfile)->mi_sem); 2611244a6d7SRyusuke Konishi return ret; 2621244a6d7SRyusuke Konishi } 2631244a6d7SRyusuke Konishi 2641244a6d7SRyusuke Konishi /** 265d37db936SRyusuke Konishi * nilfs_cpfile_create_checkpoint - create a checkpoint entry on cpfile 266d37db936SRyusuke Konishi * @cpfile: checkpoint file inode 267d37db936SRyusuke Konishi * @cno: number of checkpoint to set up 268d37db936SRyusuke Konishi * 269d37db936SRyusuke Konishi * This function creates a checkpoint with the number specified by @cno on 270d37db936SRyusuke Konishi * cpfile. If the specified checkpoint entry already exists due to a past 271d37db936SRyusuke Konishi * failure, it will be reused without returning an error. 272d37db936SRyusuke Konishi * In either case, the buffer of the block containing the checkpoint entry 273d37db936SRyusuke Konishi * and the cpfile inode are made dirty for inclusion in the write log. 274d37db936SRyusuke Konishi * 275d37db936SRyusuke Konishi * Return: 0 on success, or the following negative error code on failure. 276d37db936SRyusuke Konishi * * %-ENOMEM - Insufficient memory available. 277d37db936SRyusuke Konishi * * %-EIO - I/O error (including metadata corruption). 278d37db936SRyusuke Konishi * * %-EROFS - Read only filesystem 279d37db936SRyusuke Konishi */ 280d37db936SRyusuke Konishi int nilfs_cpfile_create_checkpoint(struct inode *cpfile, __u64 cno) 281d37db936SRyusuke Konishi { 282d37db936SRyusuke Konishi struct buffer_head *header_bh, *cp_bh; 283d37db936SRyusuke Konishi struct nilfs_cpfile_header *header; 284d37db936SRyusuke Konishi struct nilfs_checkpoint *cp; 285d37db936SRyusuke Konishi void *kaddr; 286d37db936SRyusuke Konishi int ret; 287d37db936SRyusuke Konishi 288d37db936SRyusuke Konishi if (WARN_ON_ONCE(cno < 1)) 289d37db936SRyusuke Konishi return -EIO; 290d37db936SRyusuke Konishi 291d37db936SRyusuke Konishi down_write(&NILFS_MDT(cpfile)->mi_sem); 292d37db936SRyusuke Konishi ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); 293*d07d8ba4SRyusuke Konishi if (unlikely(ret < 0)) 294d37db936SRyusuke Konishi goto out_sem; 295*d07d8ba4SRyusuke Konishi 296d37db936SRyusuke Konishi ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 1, &cp_bh); 297d37db936SRyusuke Konishi if (unlikely(ret < 0)) 298d37db936SRyusuke Konishi goto out_header; 299d37db936SRyusuke Konishi 300d37db936SRyusuke Konishi kaddr = kmap_local_page(cp_bh->b_page); 301d37db936SRyusuke Konishi cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr); 302d37db936SRyusuke Konishi if (nilfs_checkpoint_invalid(cp)) { 303d37db936SRyusuke Konishi /* a newly-created checkpoint */ 304d37db936SRyusuke Konishi nilfs_checkpoint_clear_invalid(cp); 305d37db936SRyusuke Konishi if (!nilfs_cpfile_is_in_first(cpfile, cno)) 306d37db936SRyusuke Konishi nilfs_cpfile_block_add_valid_checkpoints(cpfile, cp_bh, 307d37db936SRyusuke Konishi kaddr, 1); 308d37db936SRyusuke Konishi kunmap_local(kaddr); 309d37db936SRyusuke Konishi 310d37db936SRyusuke Konishi kaddr = kmap_local_page(header_bh->b_page); 311d37db936SRyusuke Konishi header = nilfs_cpfile_block_get_header(cpfile, header_bh, 312d37db936SRyusuke Konishi kaddr); 313d37db936SRyusuke Konishi le64_add_cpu(&header->ch_ncheckpoints, 1); 314d37db936SRyusuke Konishi kunmap_local(kaddr); 315d37db936SRyusuke Konishi mark_buffer_dirty(header_bh); 316d37db936SRyusuke Konishi } else { 317d37db936SRyusuke Konishi kunmap_local(kaddr); 318d37db936SRyusuke Konishi } 319d37db936SRyusuke Konishi 320d37db936SRyusuke Konishi /* Force the buffer and the inode to become dirty */ 321d37db936SRyusuke Konishi mark_buffer_dirty(cp_bh); 322d37db936SRyusuke Konishi brelse(cp_bh); 323d37db936SRyusuke Konishi nilfs_mdt_mark_dirty(cpfile); 324d37db936SRyusuke Konishi 325d37db936SRyusuke Konishi out_header: 326d37db936SRyusuke Konishi brelse(header_bh); 327d37db936SRyusuke Konishi 328d37db936SRyusuke Konishi out_sem: 329d37db936SRyusuke Konishi up_write(&NILFS_MDT(cpfile)->mi_sem); 330d37db936SRyusuke Konishi return ret; 331d37db936SRyusuke Konishi } 332d37db936SRyusuke Konishi 333d37db936SRyusuke Konishi /** 334cce259b4SRyusuke Konishi * nilfs_cpfile_finalize_checkpoint - fill in a checkpoint entry in cpfile 335cce259b4SRyusuke Konishi * @cpfile: checkpoint file inode 336cce259b4SRyusuke Konishi * @cno: checkpoint number 337cce259b4SRyusuke Konishi * @root: nilfs root object 338cce259b4SRyusuke Konishi * @blkinc: number of blocks added by this checkpoint 339cce259b4SRyusuke Konishi * @ctime: checkpoint creation time 340cce259b4SRyusuke Konishi * @minor: minor checkpoint flag 341cce259b4SRyusuke Konishi * 342cce259b4SRyusuke Konishi * This function completes the checkpoint entry numbered by @cno in the 343cce259b4SRyusuke Konishi * cpfile with the data given by the arguments @root, @blkinc, @ctime, and 344cce259b4SRyusuke Konishi * @minor. 345cce259b4SRyusuke Konishi * 346cce259b4SRyusuke Konishi * Return: 0 on success, or the following negative error code on failure. 347cce259b4SRyusuke Konishi * * %-ENOMEM - Insufficient memory available. 348cce259b4SRyusuke Konishi * * %-EIO - I/O error (including metadata corruption). 349cce259b4SRyusuke Konishi */ 350cce259b4SRyusuke Konishi int nilfs_cpfile_finalize_checkpoint(struct inode *cpfile, __u64 cno, 351cce259b4SRyusuke Konishi struct nilfs_root *root, __u64 blkinc, 352cce259b4SRyusuke Konishi time64_t ctime, bool minor) 353cce259b4SRyusuke Konishi { 354cce259b4SRyusuke Konishi struct buffer_head *cp_bh; 355cce259b4SRyusuke Konishi struct nilfs_checkpoint *cp; 356cce259b4SRyusuke Konishi void *kaddr; 357cce259b4SRyusuke Konishi int ret; 358cce259b4SRyusuke Konishi 359cce259b4SRyusuke Konishi if (WARN_ON_ONCE(cno < 1)) 360cce259b4SRyusuke Konishi return -EIO; 361cce259b4SRyusuke Konishi 362cce259b4SRyusuke Konishi down_write(&NILFS_MDT(cpfile)->mi_sem); 363cce259b4SRyusuke Konishi ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); 364cce259b4SRyusuke Konishi if (unlikely(ret < 0)) { 365cce259b4SRyusuke Konishi if (ret == -ENOENT) 366cce259b4SRyusuke Konishi goto error; 367cce259b4SRyusuke Konishi goto out_sem; 368cce259b4SRyusuke Konishi } 369cce259b4SRyusuke Konishi 370cce259b4SRyusuke Konishi kaddr = kmap_local_page(cp_bh->b_page); 371cce259b4SRyusuke Konishi cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr); 372cce259b4SRyusuke Konishi if (unlikely(nilfs_checkpoint_invalid(cp))) { 373cce259b4SRyusuke Konishi kunmap_local(kaddr); 374cce259b4SRyusuke Konishi brelse(cp_bh); 375cce259b4SRyusuke Konishi goto error; 376cce259b4SRyusuke Konishi } 377cce259b4SRyusuke Konishi 378cce259b4SRyusuke Konishi cp->cp_snapshot_list.ssl_next = 0; 379cce259b4SRyusuke Konishi cp->cp_snapshot_list.ssl_prev = 0; 380cce259b4SRyusuke Konishi cp->cp_inodes_count = cpu_to_le64(atomic64_read(&root->inodes_count)); 381cce259b4SRyusuke Konishi cp->cp_blocks_count = cpu_to_le64(atomic64_read(&root->blocks_count)); 382cce259b4SRyusuke Konishi cp->cp_nblk_inc = cpu_to_le64(blkinc); 383cce259b4SRyusuke Konishi cp->cp_create = cpu_to_le64(ctime); 384cce259b4SRyusuke Konishi cp->cp_cno = cpu_to_le64(cno); 385cce259b4SRyusuke Konishi 386cce259b4SRyusuke Konishi if (minor) 387cce259b4SRyusuke Konishi nilfs_checkpoint_set_minor(cp); 388cce259b4SRyusuke Konishi else 389cce259b4SRyusuke Konishi nilfs_checkpoint_clear_minor(cp); 390cce259b4SRyusuke Konishi 391cce259b4SRyusuke Konishi nilfs_write_inode_common(root->ifile, &cp->cp_ifile_inode); 392cce259b4SRyusuke Konishi nilfs_bmap_write(NILFS_I(root->ifile)->i_bmap, &cp->cp_ifile_inode); 393cce259b4SRyusuke Konishi 394cce259b4SRyusuke Konishi kunmap_local(kaddr); 395cce259b4SRyusuke Konishi brelse(cp_bh); 396cce259b4SRyusuke Konishi out_sem: 397cce259b4SRyusuke Konishi up_write(&NILFS_MDT(cpfile)->mi_sem); 398cce259b4SRyusuke Konishi return ret; 399cce259b4SRyusuke Konishi 400cce259b4SRyusuke Konishi error: 401cce259b4SRyusuke Konishi nilfs_error(cpfile->i_sb, 402cce259b4SRyusuke Konishi "checkpoint finalization failed due to metadata corruption."); 403cce259b4SRyusuke Konishi ret = -EIO; 404cce259b4SRyusuke Konishi goto out_sem; 405cce259b4SRyusuke Konishi } 406cce259b4SRyusuke Konishi 407cce259b4SRyusuke Konishi /** 40829619809SKoji Sato * nilfs_cpfile_delete_checkpoints - delete checkpoints 40929619809SKoji Sato * @cpfile: inode of checkpoint file 41029619809SKoji Sato * @start: start checkpoint number 411312f79c4SLu Jialin * @end: end checkpoint number 41229619809SKoji Sato * 41329619809SKoji Sato * Description: nilfs_cpfile_delete_checkpoints() deletes the checkpoints in 41429619809SKoji Sato * the period from @start to @end, excluding @end itself. The checkpoints 41529619809SKoji Sato * which have been already deleted are ignored. 41629619809SKoji Sato * 41729619809SKoji Sato * Return Value: On success, 0 is returned. On error, one of the following 41829619809SKoji Sato * negative error codes is returned. 41929619809SKoji Sato * 42029619809SKoji Sato * %-EIO - I/O error. 42129619809SKoji Sato * 42229619809SKoji Sato * %-ENOMEM - Insufficient amount of memory available. 42329619809SKoji Sato * 42429619809SKoji Sato * %-EINVAL - invalid checkpoints. 42529619809SKoji Sato */ 42629619809SKoji Sato int nilfs_cpfile_delete_checkpoints(struct inode *cpfile, 42729619809SKoji Sato __u64 start, 42829619809SKoji Sato __u64 end) 42929619809SKoji Sato { 43029619809SKoji Sato struct buffer_head *header_bh, *cp_bh; 43129619809SKoji Sato struct nilfs_cpfile_header *header; 43229619809SKoji Sato struct nilfs_checkpoint *cp; 43329619809SKoji Sato size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size; 43429619809SKoji Sato __u64 cno; 43529619809SKoji Sato void *kaddr; 43629619809SKoji Sato unsigned long tnicps; 437fe0627e7SRyusuke Konishi int ret, ncps, nicps, nss, count, i; 43829619809SKoji Sato 4391f5abe7eSRyusuke Konishi if (unlikely(start == 0 || start > end)) { 440a1d0747aSJoe Perches nilfs_err(cpfile->i_sb, 441feee880fSRyusuke Konishi "cannot delete checkpoints: invalid range [%llu, %llu)", 4421f5abe7eSRyusuke Konishi (unsigned long long)start, (unsigned long long)end); 4431f5abe7eSRyusuke Konishi return -EINVAL; 44429619809SKoji Sato } 44529619809SKoji Sato 44629619809SKoji Sato down_write(&NILFS_MDT(cpfile)->mi_sem); 44729619809SKoji Sato 44829619809SKoji Sato ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); 44929619809SKoji Sato if (ret < 0) 45029619809SKoji Sato goto out_sem; 45129619809SKoji Sato tnicps = 0; 452fe0627e7SRyusuke Konishi nss = 0; 45329619809SKoji Sato 45429619809SKoji Sato for (cno = start; cno < end; cno += ncps) { 45529619809SKoji Sato ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, end); 45629619809SKoji Sato ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); 45729619809SKoji Sato if (ret < 0) { 45829619809SKoji Sato if (ret != -ENOENT) 459d9a0a345SJiro SEKIBA break; 46029619809SKoji Sato /* skip hole */ 46129619809SKoji Sato ret = 0; 46229619809SKoji Sato continue; 46329619809SKoji Sato } 46429619809SKoji Sato 4655eccc067SRyusuke Konishi kaddr = kmap_local_page(cp_bh->b_page); 46629619809SKoji Sato cp = nilfs_cpfile_block_get_checkpoint( 46729619809SKoji Sato cpfile, cno, cp_bh, kaddr); 46829619809SKoji Sato nicps = 0; 46929619809SKoji Sato for (i = 0; i < ncps; i++, cp = (void *)cp + cpsz) { 470fe0627e7SRyusuke Konishi if (nilfs_checkpoint_snapshot(cp)) { 471fe0627e7SRyusuke Konishi nss++; 472fe0627e7SRyusuke Konishi } else if (!nilfs_checkpoint_invalid(cp)) { 47329619809SKoji Sato nilfs_checkpoint_set_invalid(cp); 47429619809SKoji Sato nicps++; 47529619809SKoji Sato } 47629619809SKoji Sato } 47729619809SKoji Sato if (nicps > 0) { 47829619809SKoji Sato tnicps += nicps; 4795fc7b141SRyusuke Konishi mark_buffer_dirty(cp_bh); 48029619809SKoji Sato nilfs_mdt_mark_dirty(cpfile); 4815ee58148SJiro SEKIBA if (!nilfs_cpfile_is_in_first(cpfile, cno)) { 4825ee58148SJiro SEKIBA count = 4835ee58148SJiro SEKIBA nilfs_cpfile_block_sub_valid_checkpoints( 4845ee58148SJiro SEKIBA cpfile, cp_bh, kaddr, nicps); 4855ee58148SJiro SEKIBA if (count == 0) { 48629619809SKoji Sato /* make hole */ 4875eccc067SRyusuke Konishi kunmap_local(kaddr); 48829619809SKoji Sato brelse(cp_bh); 4895ee58148SJiro SEKIBA ret = 4905ee58148SJiro SEKIBA nilfs_cpfile_delete_checkpoint_block( 49129619809SKoji Sato cpfile, cno); 49229619809SKoji Sato if (ret == 0) 49329619809SKoji Sato continue; 494a1d0747aSJoe Perches nilfs_err(cpfile->i_sb, 495feee880fSRyusuke Konishi "error %d deleting checkpoint block", 496feee880fSRyusuke Konishi ret); 497d9a0a345SJiro SEKIBA break; 49829619809SKoji Sato } 49929619809SKoji Sato } 5005ee58148SJiro SEKIBA } 50129619809SKoji Sato 5025eccc067SRyusuke Konishi kunmap_local(kaddr); 50329619809SKoji Sato brelse(cp_bh); 50429619809SKoji Sato } 50529619809SKoji Sato 50629619809SKoji Sato if (tnicps > 0) { 5075eccc067SRyusuke Konishi kaddr = kmap_local_page(header_bh->b_page); 50829619809SKoji Sato header = nilfs_cpfile_block_get_header(cpfile, header_bh, 50929619809SKoji Sato kaddr); 5106c98cd4eSKoji Sato le64_add_cpu(&header->ch_ncheckpoints, -(u64)tnicps); 5115fc7b141SRyusuke Konishi mark_buffer_dirty(header_bh); 51229619809SKoji Sato nilfs_mdt_mark_dirty(cpfile); 5135eccc067SRyusuke Konishi kunmap_local(kaddr); 51429619809SKoji Sato } 51562013ab5SRyusuke Konishi 51629619809SKoji Sato brelse(header_bh); 517fe0627e7SRyusuke Konishi if (nss > 0) 518fe0627e7SRyusuke Konishi ret = -EBUSY; 51929619809SKoji Sato 52029619809SKoji Sato out_sem: 52129619809SKoji Sato up_write(&NILFS_MDT(cpfile)->mi_sem); 52229619809SKoji Sato return ret; 52329619809SKoji Sato } 52429619809SKoji Sato 52529619809SKoji Sato static void nilfs_cpfile_checkpoint_to_cpinfo(struct inode *cpfile, 52629619809SKoji Sato struct nilfs_checkpoint *cp, 52729619809SKoji Sato struct nilfs_cpinfo *ci) 52829619809SKoji Sato { 52929619809SKoji Sato ci->ci_flags = le32_to_cpu(cp->cp_flags); 53029619809SKoji Sato ci->ci_cno = le64_to_cpu(cp->cp_cno); 53129619809SKoji Sato ci->ci_create = le64_to_cpu(cp->cp_create); 53229619809SKoji Sato ci->ci_nblk_inc = le64_to_cpu(cp->cp_nblk_inc); 53329619809SKoji Sato ci->ci_inodes_count = le64_to_cpu(cp->cp_inodes_count); 53429619809SKoji Sato ci->ci_blocks_count = le64_to_cpu(cp->cp_blocks_count); 53529619809SKoji Sato ci->ci_next = le64_to_cpu(cp->cp_snapshot_list.ssl_next); 53629619809SKoji Sato } 53729619809SKoji Sato 53876068c4fSRyusuke Konishi static ssize_t nilfs_cpfile_do_get_cpinfo(struct inode *cpfile, __u64 *cnop, 5390c6c44cbSRyusuke Konishi void *buf, unsigned int cisz, 5400c6c44cbSRyusuke Konishi size_t nci) 54129619809SKoji Sato { 54229619809SKoji Sato struct nilfs_checkpoint *cp; 543003ff182SRyusuke Konishi struct nilfs_cpinfo *ci = buf; 54429619809SKoji Sato struct buffer_head *bh; 54529619809SKoji Sato size_t cpsz = NILFS_MDT(cpfile)->mi_entry_size; 54676068c4fSRyusuke Konishi __u64 cur_cno = nilfs_mdt_cno(cpfile), cno = *cnop; 54729619809SKoji Sato void *kaddr; 54829619809SKoji Sato int n, ret; 54929619809SKoji Sato int ncps, i; 55029619809SKoji Sato 5511f5abe7eSRyusuke Konishi if (cno == 0) 5521f5abe7eSRyusuke Konishi return -ENOENT; /* checkpoint number 0 is invalid */ 55329619809SKoji Sato down_read(&NILFS_MDT(cpfile)->mi_sem); 55429619809SKoji Sato 55553a2c3bdSRyusuke Konishi for (n = 0; n < nci; cno += ncps) { 55653a2c3bdSRyusuke Konishi ret = nilfs_cpfile_find_checkpoint_block( 55753a2c3bdSRyusuke Konishi cpfile, cno, cur_cno - 1, &cno, &bh); 55829619809SKoji Sato if (ret < 0) { 55953a2c3bdSRyusuke Konishi if (likely(ret == -ENOENT)) 56053a2c3bdSRyusuke Konishi break; 56129619809SKoji Sato goto out; 56229619809SKoji Sato } 56353a2c3bdSRyusuke Konishi ncps = nilfs_cpfile_checkpoints_in_block(cpfile, cno, cur_cno); 56429619809SKoji Sato 5655eccc067SRyusuke Konishi kaddr = kmap_local_page(bh->b_page); 56629619809SKoji Sato cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); 56729619809SKoji Sato for (i = 0; i < ncps && n < nci; i++, cp = (void *)cp + cpsz) { 568003ff182SRyusuke Konishi if (!nilfs_checkpoint_invalid(cp)) { 569003ff182SRyusuke Konishi nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, 570003ff182SRyusuke Konishi ci); 571003ff182SRyusuke Konishi ci = (void *)ci + cisz; 572003ff182SRyusuke Konishi n++; 573003ff182SRyusuke Konishi } 57429619809SKoji Sato } 5755eccc067SRyusuke Konishi kunmap_local(kaddr); 57629619809SKoji Sato brelse(bh); 57729619809SKoji Sato } 57829619809SKoji Sato 57929619809SKoji Sato ret = n; 580003ff182SRyusuke Konishi if (n > 0) { 581003ff182SRyusuke Konishi ci = (void *)ci - cisz; 582003ff182SRyusuke Konishi *cnop = ci->ci_cno + 1; 583003ff182SRyusuke Konishi } 58429619809SKoji Sato 58529619809SKoji Sato out: 58629619809SKoji Sato up_read(&NILFS_MDT(cpfile)->mi_sem); 58729619809SKoji Sato return ret; 58829619809SKoji Sato } 58929619809SKoji Sato 590b028fcfcSRyusuke Konishi static ssize_t nilfs_cpfile_do_get_ssinfo(struct inode *cpfile, __u64 *cnop, 5910c6c44cbSRyusuke Konishi void *buf, unsigned int cisz, 5920c6c44cbSRyusuke Konishi size_t nci) 59329619809SKoji Sato { 59429619809SKoji Sato struct buffer_head *bh; 59529619809SKoji Sato struct nilfs_cpfile_header *header; 59629619809SKoji Sato struct nilfs_checkpoint *cp; 597003ff182SRyusuke Konishi struct nilfs_cpinfo *ci = buf; 598b028fcfcSRyusuke Konishi __u64 curr = *cnop, next; 59929619809SKoji Sato unsigned long curr_blkoff, next_blkoff; 60029619809SKoji Sato void *kaddr; 6017fa10d20SRyusuke Konishi int n = 0, ret; 60229619809SKoji Sato 60329619809SKoji Sato down_read(&NILFS_MDT(cpfile)->mi_sem); 60429619809SKoji Sato 605b028fcfcSRyusuke Konishi if (curr == 0) { 60629619809SKoji Sato ret = nilfs_cpfile_get_header_block(cpfile, &bh); 60729619809SKoji Sato if (ret < 0) 60829619809SKoji Sato goto out; 6095eccc067SRyusuke Konishi kaddr = kmap_local_page(bh->b_page); 61029619809SKoji Sato header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr); 61129619809SKoji Sato curr = le64_to_cpu(header->ch_snapshot_list.ssl_next); 6125eccc067SRyusuke Konishi kunmap_local(kaddr); 61329619809SKoji Sato brelse(bh); 61429619809SKoji Sato if (curr == 0) { 61529619809SKoji Sato ret = 0; 61629619809SKoji Sato goto out; 61729619809SKoji Sato } 618b028fcfcSRyusuke Konishi } else if (unlikely(curr == ~(__u64)0)) { 619b028fcfcSRyusuke Konishi ret = 0; 620b028fcfcSRyusuke Konishi goto out; 621b028fcfcSRyusuke Konishi } 622b028fcfcSRyusuke Konishi 62329619809SKoji Sato curr_blkoff = nilfs_cpfile_get_blkoff(cpfile, curr); 62429619809SKoji Sato ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr, 0, &bh); 6257fa10d20SRyusuke Konishi if (unlikely(ret < 0)) { 6267fa10d20SRyusuke Konishi if (ret == -ENOENT) 6277fa10d20SRyusuke Konishi ret = 0; /* No snapshots (started from a hole block) */ 62829619809SKoji Sato goto out; 62929619809SKoji Sato } 6305eccc067SRyusuke Konishi kaddr = kmap_local_page(bh->b_page); 6317fa10d20SRyusuke Konishi while (n < nci) { 6327fa10d20SRyusuke Konishi cp = nilfs_cpfile_block_get_checkpoint(cpfile, curr, bh, kaddr); 6337fa10d20SRyusuke Konishi curr = ~(__u64)0; /* Terminator */ 6347fa10d20SRyusuke Konishi if (unlikely(nilfs_checkpoint_invalid(cp) || 6357fa10d20SRyusuke Konishi !nilfs_checkpoint_snapshot(cp))) 6367fa10d20SRyusuke Konishi break; 637003ff182SRyusuke Konishi nilfs_cpfile_checkpoint_to_cpinfo(cpfile, cp, ci); 638003ff182SRyusuke Konishi ci = (void *)ci + cisz; 639003ff182SRyusuke Konishi n++; 6407fa10d20SRyusuke Konishi next = le64_to_cpu(cp->cp_snapshot_list.ssl_next); 6417fa10d20SRyusuke Konishi if (next == 0) 6427fa10d20SRyusuke Konishi break; /* reach end of the snapshot list */ 6437fa10d20SRyusuke Konishi 64429619809SKoji Sato next_blkoff = nilfs_cpfile_get_blkoff(cpfile, next); 64529619809SKoji Sato if (curr_blkoff != next_blkoff) { 6465eccc067SRyusuke Konishi kunmap_local(kaddr); 64729619809SKoji Sato brelse(bh); 64829619809SKoji Sato ret = nilfs_cpfile_get_checkpoint_block(cpfile, next, 64929619809SKoji Sato 0, &bh); 6507fa10d20SRyusuke Konishi if (unlikely(ret < 0)) { 6517fa10d20SRyusuke Konishi WARN_ON(ret == -ENOENT); 65229619809SKoji Sato goto out; 6537fa10d20SRyusuke Konishi } 6545eccc067SRyusuke Konishi kaddr = kmap_local_page(bh->b_page); 65529619809SKoji Sato } 65629619809SKoji Sato curr = next; 65729619809SKoji Sato curr_blkoff = next_blkoff; 65829619809SKoji Sato } 6595eccc067SRyusuke Konishi kunmap_local(kaddr); 66029619809SKoji Sato brelse(bh); 661b028fcfcSRyusuke Konishi *cnop = curr; 66229619809SKoji Sato ret = n; 66329619809SKoji Sato 66429619809SKoji Sato out: 66529619809SKoji Sato up_read(&NILFS_MDT(cpfile)->mi_sem); 66629619809SKoji Sato return ret; 66729619809SKoji Sato } 66829619809SKoji Sato 66929619809SKoji Sato /** 6708e226a0aSRandy Dunlap * nilfs_cpfile_get_cpinfo - get information on checkpoints 6718e226a0aSRandy Dunlap * @cpfile: checkpoint file inode 6728e226a0aSRandy Dunlap * @cnop: place to pass a starting checkpoint number and receive a 6738e226a0aSRandy Dunlap * checkpoint number to continue the search 6748e226a0aSRandy Dunlap * @mode: mode of checkpoints that the caller wants to retrieve 6758e226a0aSRandy Dunlap * @buf: buffer for storing checkpoints' information 6768e226a0aSRandy Dunlap * @cisz: byte size of one checkpoint info item in array 6778e226a0aSRandy Dunlap * @nci: number of checkpoint info items to retrieve 6788e226a0aSRandy Dunlap * 6798e226a0aSRandy Dunlap * nilfs_cpfile_get_cpinfo() searches for checkpoints in @mode state 6808e226a0aSRandy Dunlap * starting from the checkpoint number stored in @cnop, and stores 6818e226a0aSRandy Dunlap * information about found checkpoints in @buf. 6828e226a0aSRandy Dunlap * The buffer pointed to by @buf must be large enough to store information 6838e226a0aSRandy Dunlap * for @nci checkpoints. If at least one checkpoint information is 6848e226a0aSRandy Dunlap * successfully retrieved, @cnop is updated to point to the checkpoint 6858e226a0aSRandy Dunlap * number to continue searching. 6868e226a0aSRandy Dunlap * 6878e226a0aSRandy Dunlap * Return: Count of checkpoint info items stored in the output buffer on 6888e226a0aSRandy Dunlap * success, or the following negative error code on failure. 6898e226a0aSRandy Dunlap * * %-EINVAL - Invalid checkpoint mode. 6908e226a0aSRandy Dunlap * * %-ENOMEM - Insufficient memory available. 6918e226a0aSRandy Dunlap * * %-EIO - I/O error (including metadata corruption). 6928e226a0aSRandy Dunlap * * %-ENOENT - Invalid checkpoint number specified. 69329619809SKoji Sato */ 694b028fcfcSRyusuke Konishi 695b028fcfcSRyusuke Konishi ssize_t nilfs_cpfile_get_cpinfo(struct inode *cpfile, __u64 *cnop, int mode, 6960c6c44cbSRyusuke Konishi void *buf, unsigned int cisz, size_t nci) 69729619809SKoji Sato { 69829619809SKoji Sato switch (mode) { 69929619809SKoji Sato case NILFS_CHECKPOINT: 700003ff182SRyusuke Konishi return nilfs_cpfile_do_get_cpinfo(cpfile, cnop, buf, cisz, nci); 70129619809SKoji Sato case NILFS_SNAPSHOT: 702003ff182SRyusuke Konishi return nilfs_cpfile_do_get_ssinfo(cpfile, cnop, buf, cisz, nci); 70329619809SKoji Sato default: 70429619809SKoji Sato return -EINVAL; 70529619809SKoji Sato } 70629619809SKoji Sato } 70729619809SKoji Sato 70829619809SKoji Sato /** 709caaab566SRyusuke Konishi * nilfs_cpfile_delete_checkpoint - delete a checkpoint 710caaab566SRyusuke Konishi * @cpfile: checkpoint file inode 711caaab566SRyusuke Konishi * @cno: checkpoint number to delete 712caaab566SRyusuke Konishi * 713caaab566SRyusuke Konishi * Return: 0 on success, or the following negative error code on failure. 714caaab566SRyusuke Konishi * * %-EBUSY - Checkpoint in use (snapshot specified). 715caaab566SRyusuke Konishi * * %-EIO - I/O error (including metadata corruption). 716caaab566SRyusuke Konishi * * %-ENOENT - No valid checkpoint found. 717caaab566SRyusuke Konishi * * %-ENOMEM - Insufficient memory available. 71829619809SKoji Sato */ 71929619809SKoji Sato int nilfs_cpfile_delete_checkpoint(struct inode *cpfile, __u64 cno) 72029619809SKoji Sato { 72129619809SKoji Sato struct nilfs_cpinfo ci; 72276068c4fSRyusuke Konishi __u64 tcno = cno; 72329619809SKoji Sato ssize_t nci; 72429619809SKoji Sato 725003ff182SRyusuke Konishi nci = nilfs_cpfile_do_get_cpinfo(cpfile, &tcno, &ci, sizeof(ci), 1); 72629619809SKoji Sato if (nci < 0) 72729619809SKoji Sato return nci; 72829619809SKoji Sato else if (nci == 0 || ci.ci_cno != cno) 72929619809SKoji Sato return -ENOENT; 73030c25be7SRyusuke Konishi else if (nilfs_cpinfo_snapshot(&ci)) 73130c25be7SRyusuke Konishi return -EBUSY; 73229619809SKoji Sato 73329619809SKoji Sato return nilfs_cpfile_delete_checkpoints(cpfile, cno, cno + 1); 73429619809SKoji Sato } 73529619809SKoji Sato 73629619809SKoji Sato static struct nilfs_snapshot_list * 73729619809SKoji Sato nilfs_cpfile_block_get_snapshot_list(const struct inode *cpfile, 73829619809SKoji Sato __u64 cno, 73929619809SKoji Sato struct buffer_head *bh, 74029619809SKoji Sato void *kaddr) 74129619809SKoji Sato { 74229619809SKoji Sato struct nilfs_cpfile_header *header; 74329619809SKoji Sato struct nilfs_checkpoint *cp; 74429619809SKoji Sato struct nilfs_snapshot_list *list; 74529619809SKoji Sato 74629619809SKoji Sato if (cno != 0) { 74729619809SKoji Sato cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); 74829619809SKoji Sato list = &cp->cp_snapshot_list; 74929619809SKoji Sato } else { 75029619809SKoji Sato header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr); 75129619809SKoji Sato list = &header->ch_snapshot_list; 75229619809SKoji Sato } 75329619809SKoji Sato return list; 75429619809SKoji Sato } 75529619809SKoji Sato 75629619809SKoji Sato static int nilfs_cpfile_set_snapshot(struct inode *cpfile, __u64 cno) 75729619809SKoji Sato { 75829619809SKoji Sato struct buffer_head *header_bh, *curr_bh, *prev_bh, *cp_bh; 75929619809SKoji Sato struct nilfs_cpfile_header *header; 76029619809SKoji Sato struct nilfs_checkpoint *cp; 76129619809SKoji Sato struct nilfs_snapshot_list *list; 76229619809SKoji Sato __u64 curr, prev; 76329619809SKoji Sato unsigned long curr_blkoff, prev_blkoff; 76429619809SKoji Sato void *kaddr; 76529619809SKoji Sato int ret; 76629619809SKoji Sato 7671f5abe7eSRyusuke Konishi if (cno == 0) 7681f5abe7eSRyusuke Konishi return -ENOENT; /* checkpoint number 0 is invalid */ 76929619809SKoji Sato down_write(&NILFS_MDT(cpfile)->mi_sem); 77029619809SKoji Sato 77129619809SKoji Sato ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); 77229619809SKoji Sato if (ret < 0) 77329619809SKoji Sato goto out_sem; 7745eccc067SRyusuke Konishi kaddr = kmap_local_page(cp_bh->b_page); 77529619809SKoji Sato cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr); 77629619809SKoji Sato if (nilfs_checkpoint_invalid(cp)) { 77729619809SKoji Sato ret = -ENOENT; 7785eccc067SRyusuke Konishi kunmap_local(kaddr); 77929619809SKoji Sato goto out_cp; 78029619809SKoji Sato } 78129619809SKoji Sato if (nilfs_checkpoint_snapshot(cp)) { 78229619809SKoji Sato ret = 0; 7835eccc067SRyusuke Konishi kunmap_local(kaddr); 78429619809SKoji Sato goto out_cp; 78529619809SKoji Sato } 7865eccc067SRyusuke Konishi kunmap_local(kaddr); 78729619809SKoji Sato 78829619809SKoji Sato ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); 78929619809SKoji Sato if (ret < 0) 79029619809SKoji Sato goto out_cp; 7915eccc067SRyusuke Konishi kaddr = kmap_local_page(header_bh->b_page); 79229619809SKoji Sato header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr); 79329619809SKoji Sato list = &header->ch_snapshot_list; 79429619809SKoji Sato curr_bh = header_bh; 79529619809SKoji Sato get_bh(curr_bh); 79629619809SKoji Sato curr = 0; 79729619809SKoji Sato curr_blkoff = 0; 79829619809SKoji Sato prev = le64_to_cpu(list->ssl_prev); 79929619809SKoji Sato while (prev > cno) { 80029619809SKoji Sato prev_blkoff = nilfs_cpfile_get_blkoff(cpfile, prev); 80129619809SKoji Sato curr = prev; 80229619809SKoji Sato if (curr_blkoff != prev_blkoff) { 8035eccc067SRyusuke Konishi kunmap_local(kaddr); 80429619809SKoji Sato brelse(curr_bh); 80529619809SKoji Sato ret = nilfs_cpfile_get_checkpoint_block(cpfile, curr, 80629619809SKoji Sato 0, &curr_bh); 80729619809SKoji Sato if (ret < 0) 80829619809SKoji Sato goto out_header; 8095eccc067SRyusuke Konishi kaddr = kmap_local_page(curr_bh->b_page); 81029619809SKoji Sato } 81129619809SKoji Sato curr_blkoff = prev_blkoff; 81229619809SKoji Sato cp = nilfs_cpfile_block_get_checkpoint( 81329619809SKoji Sato cpfile, curr, curr_bh, kaddr); 81429619809SKoji Sato list = &cp->cp_snapshot_list; 81529619809SKoji Sato prev = le64_to_cpu(list->ssl_prev); 81629619809SKoji Sato } 8175eccc067SRyusuke Konishi kunmap_local(kaddr); 81829619809SKoji Sato 81929619809SKoji Sato if (prev != 0) { 82029619809SKoji Sato ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0, 82129619809SKoji Sato &prev_bh); 82229619809SKoji Sato if (ret < 0) 82329619809SKoji Sato goto out_curr; 82429619809SKoji Sato } else { 82529619809SKoji Sato prev_bh = header_bh; 82629619809SKoji Sato get_bh(prev_bh); 82729619809SKoji Sato } 82829619809SKoji Sato 8295eccc067SRyusuke Konishi kaddr = kmap_local_page(curr_bh->b_page); 83029619809SKoji Sato list = nilfs_cpfile_block_get_snapshot_list( 83129619809SKoji Sato cpfile, curr, curr_bh, kaddr); 83229619809SKoji Sato list->ssl_prev = cpu_to_le64(cno); 8335eccc067SRyusuke Konishi kunmap_local(kaddr); 83429619809SKoji Sato 8355eccc067SRyusuke Konishi kaddr = kmap_local_page(cp_bh->b_page); 83629619809SKoji Sato cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr); 83729619809SKoji Sato cp->cp_snapshot_list.ssl_next = cpu_to_le64(curr); 83829619809SKoji Sato cp->cp_snapshot_list.ssl_prev = cpu_to_le64(prev); 83929619809SKoji Sato nilfs_checkpoint_set_snapshot(cp); 8405eccc067SRyusuke Konishi kunmap_local(kaddr); 84129619809SKoji Sato 8425eccc067SRyusuke Konishi kaddr = kmap_local_page(prev_bh->b_page); 84329619809SKoji Sato list = nilfs_cpfile_block_get_snapshot_list( 84429619809SKoji Sato cpfile, prev, prev_bh, kaddr); 84529619809SKoji Sato list->ssl_next = cpu_to_le64(cno); 8465eccc067SRyusuke Konishi kunmap_local(kaddr); 84729619809SKoji Sato 8485eccc067SRyusuke Konishi kaddr = kmap_local_page(header_bh->b_page); 84929619809SKoji Sato header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr); 85029619809SKoji Sato le64_add_cpu(&header->ch_nsnapshots, 1); 8515eccc067SRyusuke Konishi kunmap_local(kaddr); 85229619809SKoji Sato 8535fc7b141SRyusuke Konishi mark_buffer_dirty(prev_bh); 8545fc7b141SRyusuke Konishi mark_buffer_dirty(curr_bh); 8555fc7b141SRyusuke Konishi mark_buffer_dirty(cp_bh); 8565fc7b141SRyusuke Konishi mark_buffer_dirty(header_bh); 85729619809SKoji Sato nilfs_mdt_mark_dirty(cpfile); 85829619809SKoji Sato 85929619809SKoji Sato brelse(prev_bh); 86029619809SKoji Sato 86129619809SKoji Sato out_curr: 86229619809SKoji Sato brelse(curr_bh); 86329619809SKoji Sato 86429619809SKoji Sato out_header: 86529619809SKoji Sato brelse(header_bh); 86629619809SKoji Sato 86729619809SKoji Sato out_cp: 86829619809SKoji Sato brelse(cp_bh); 86929619809SKoji Sato 87029619809SKoji Sato out_sem: 87129619809SKoji Sato up_write(&NILFS_MDT(cpfile)->mi_sem); 87229619809SKoji Sato return ret; 87329619809SKoji Sato } 87429619809SKoji Sato 87529619809SKoji Sato static int nilfs_cpfile_clear_snapshot(struct inode *cpfile, __u64 cno) 87629619809SKoji Sato { 87729619809SKoji Sato struct buffer_head *header_bh, *next_bh, *prev_bh, *cp_bh; 87829619809SKoji Sato struct nilfs_cpfile_header *header; 87929619809SKoji Sato struct nilfs_checkpoint *cp; 88029619809SKoji Sato struct nilfs_snapshot_list *list; 88129619809SKoji Sato __u64 next, prev; 88229619809SKoji Sato void *kaddr; 88329619809SKoji Sato int ret; 88429619809SKoji Sato 8851f5abe7eSRyusuke Konishi if (cno == 0) 8861f5abe7eSRyusuke Konishi return -ENOENT; /* checkpoint number 0 is invalid */ 88729619809SKoji Sato down_write(&NILFS_MDT(cpfile)->mi_sem); 88829619809SKoji Sato 88929619809SKoji Sato ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); 89029619809SKoji Sato if (ret < 0) 89129619809SKoji Sato goto out_sem; 8925eccc067SRyusuke Konishi kaddr = kmap_local_page(cp_bh->b_page); 89329619809SKoji Sato cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr); 89429619809SKoji Sato if (nilfs_checkpoint_invalid(cp)) { 89529619809SKoji Sato ret = -ENOENT; 8965eccc067SRyusuke Konishi kunmap_local(kaddr); 89729619809SKoji Sato goto out_cp; 89829619809SKoji Sato } 89929619809SKoji Sato if (!nilfs_checkpoint_snapshot(cp)) { 90029619809SKoji Sato ret = 0; 9015eccc067SRyusuke Konishi kunmap_local(kaddr); 90229619809SKoji Sato goto out_cp; 90329619809SKoji Sato } 90429619809SKoji Sato 90529619809SKoji Sato list = &cp->cp_snapshot_list; 90629619809SKoji Sato next = le64_to_cpu(list->ssl_next); 90729619809SKoji Sato prev = le64_to_cpu(list->ssl_prev); 9085eccc067SRyusuke Konishi kunmap_local(kaddr); 90929619809SKoji Sato 91029619809SKoji Sato ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); 91129619809SKoji Sato if (ret < 0) 91229619809SKoji Sato goto out_cp; 91329619809SKoji Sato if (next != 0) { 91429619809SKoji Sato ret = nilfs_cpfile_get_checkpoint_block(cpfile, next, 0, 91529619809SKoji Sato &next_bh); 91629619809SKoji Sato if (ret < 0) 91729619809SKoji Sato goto out_header; 91829619809SKoji Sato } else { 91929619809SKoji Sato next_bh = header_bh; 92029619809SKoji Sato get_bh(next_bh); 92129619809SKoji Sato } 92229619809SKoji Sato if (prev != 0) { 92329619809SKoji Sato ret = nilfs_cpfile_get_checkpoint_block(cpfile, prev, 0, 92429619809SKoji Sato &prev_bh); 92529619809SKoji Sato if (ret < 0) 92629619809SKoji Sato goto out_next; 92729619809SKoji Sato } else { 92829619809SKoji Sato prev_bh = header_bh; 92929619809SKoji Sato get_bh(prev_bh); 93029619809SKoji Sato } 93129619809SKoji Sato 9325eccc067SRyusuke Konishi kaddr = kmap_local_page(next_bh->b_page); 93329619809SKoji Sato list = nilfs_cpfile_block_get_snapshot_list( 93429619809SKoji Sato cpfile, next, next_bh, kaddr); 93529619809SKoji Sato list->ssl_prev = cpu_to_le64(prev); 9365eccc067SRyusuke Konishi kunmap_local(kaddr); 93729619809SKoji Sato 9385eccc067SRyusuke Konishi kaddr = kmap_local_page(prev_bh->b_page); 93929619809SKoji Sato list = nilfs_cpfile_block_get_snapshot_list( 94029619809SKoji Sato cpfile, prev, prev_bh, kaddr); 94129619809SKoji Sato list->ssl_next = cpu_to_le64(next); 9425eccc067SRyusuke Konishi kunmap_local(kaddr); 94329619809SKoji Sato 9445eccc067SRyusuke Konishi kaddr = kmap_local_page(cp_bh->b_page); 94529619809SKoji Sato cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, cp_bh, kaddr); 94629619809SKoji Sato cp->cp_snapshot_list.ssl_next = cpu_to_le64(0); 94729619809SKoji Sato cp->cp_snapshot_list.ssl_prev = cpu_to_le64(0); 94829619809SKoji Sato nilfs_checkpoint_clear_snapshot(cp); 9495eccc067SRyusuke Konishi kunmap_local(kaddr); 95029619809SKoji Sato 9515eccc067SRyusuke Konishi kaddr = kmap_local_page(header_bh->b_page); 95229619809SKoji Sato header = nilfs_cpfile_block_get_header(cpfile, header_bh, kaddr); 95329619809SKoji Sato le64_add_cpu(&header->ch_nsnapshots, -1); 9545eccc067SRyusuke Konishi kunmap_local(kaddr); 95529619809SKoji Sato 9565fc7b141SRyusuke Konishi mark_buffer_dirty(next_bh); 9575fc7b141SRyusuke Konishi mark_buffer_dirty(prev_bh); 9585fc7b141SRyusuke Konishi mark_buffer_dirty(cp_bh); 9595fc7b141SRyusuke Konishi mark_buffer_dirty(header_bh); 96029619809SKoji Sato nilfs_mdt_mark_dirty(cpfile); 96129619809SKoji Sato 96229619809SKoji Sato brelse(prev_bh); 96329619809SKoji Sato 96429619809SKoji Sato out_next: 96529619809SKoji Sato brelse(next_bh); 96629619809SKoji Sato 96729619809SKoji Sato out_header: 96829619809SKoji Sato brelse(header_bh); 96929619809SKoji Sato 97029619809SKoji Sato out_cp: 97129619809SKoji Sato brelse(cp_bh); 97229619809SKoji Sato 97329619809SKoji Sato out_sem: 97429619809SKoji Sato up_write(&NILFS_MDT(cpfile)->mi_sem); 97529619809SKoji Sato return ret; 97629619809SKoji Sato } 97729619809SKoji Sato 97829619809SKoji Sato /** 979caaab566SRyusuke Konishi * nilfs_cpfile_is_snapshot - determine if checkpoint is a snapshot 98029619809SKoji Sato * @cpfile: inode of checkpoint file 98129619809SKoji Sato * @cno: checkpoint number 98229619809SKoji Sato * 983caaab566SRyusuke Konishi * Return: 1 if the checkpoint specified by @cno is a snapshot, 0 if not, or 984caaab566SRyusuke Konishi * the following negative error code on failure. 985caaab566SRyusuke Konishi * * %-EIO - I/O error (including metadata corruption). 986caaab566SRyusuke Konishi * * %-ENOENT - No such checkpoint. 987caaab566SRyusuke Konishi * * %-ENOMEM - Insufficient memory available. 98829619809SKoji Sato */ 98929619809SKoji Sato int nilfs_cpfile_is_snapshot(struct inode *cpfile, __u64 cno) 99029619809SKoji Sato { 99129619809SKoji Sato struct buffer_head *bh; 99229619809SKoji Sato struct nilfs_checkpoint *cp; 99329619809SKoji Sato void *kaddr; 99429619809SKoji Sato int ret; 99529619809SKoji Sato 996076a378bSRyusuke Konishi /* 997076a378bSRyusuke Konishi * CP number is invalid if it's zero or larger than the 998076a378bSRyusuke Konishi * largest existing one. 999076a378bSRyusuke Konishi */ 100043be0ec0SZhu Yanhai if (cno == 0 || cno >= nilfs_mdt_cno(cpfile)) 100143be0ec0SZhu Yanhai return -ENOENT; 100229619809SKoji Sato down_read(&NILFS_MDT(cpfile)->mi_sem); 100329619809SKoji Sato 100429619809SKoji Sato ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh); 100529619809SKoji Sato if (ret < 0) 100629619809SKoji Sato goto out; 10075eccc067SRyusuke Konishi kaddr = kmap_local_page(bh->b_page); 100829619809SKoji Sato cp = nilfs_cpfile_block_get_checkpoint(cpfile, cno, bh, kaddr); 100943be0ec0SZhu Yanhai if (nilfs_checkpoint_invalid(cp)) 101043be0ec0SZhu Yanhai ret = -ENOENT; 101143be0ec0SZhu Yanhai else 101229619809SKoji Sato ret = nilfs_checkpoint_snapshot(cp); 10135eccc067SRyusuke Konishi kunmap_local(kaddr); 101429619809SKoji Sato brelse(bh); 101529619809SKoji Sato 101629619809SKoji Sato out: 101729619809SKoji Sato up_read(&NILFS_MDT(cpfile)->mi_sem); 101829619809SKoji Sato return ret; 101929619809SKoji Sato } 102029619809SKoji Sato 102129619809SKoji Sato /** 102229619809SKoji Sato * nilfs_cpfile_change_cpmode - change checkpoint mode 102329619809SKoji Sato * @cpfile: inode of checkpoint file 102429619809SKoji Sato * @cno: checkpoint number 102564ead520SWang Hai * @mode: mode of checkpoint 102629619809SKoji Sato * 102729619809SKoji Sato * Description: nilfs_change_cpmode() changes the mode of the checkpoint 102829619809SKoji Sato * specified by @cno. The mode @mode is NILFS_CHECKPOINT or NILFS_SNAPSHOT. 102929619809SKoji Sato * 103029619809SKoji Sato * Return Value: On success, 0 is returned. On error, one of the following 103129619809SKoji Sato * negative error codes is returned. 103229619809SKoji Sato * 103329619809SKoji Sato * %-EIO - I/O error. 103429619809SKoji Sato * 103529619809SKoji Sato * %-ENOMEM - Insufficient amount of memory available. 103629619809SKoji Sato * 103729619809SKoji Sato * %-ENOENT - No such checkpoint. 103829619809SKoji Sato */ 103929619809SKoji Sato int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode) 104029619809SKoji Sato { 104129619809SKoji Sato int ret; 104229619809SKoji Sato 104329619809SKoji Sato switch (mode) { 104429619809SKoji Sato case NILFS_CHECKPOINT: 1045032dbb3bSRyusuke Konishi if (nilfs_checkpoint_is_mounted(cpfile->i_sb, cno)) 104629619809SKoji Sato /* 1047032dbb3bSRyusuke Konishi * Current implementation does not have to protect 1048032dbb3bSRyusuke Konishi * plain read-only mounts since they are exclusive 1049032dbb3bSRyusuke Konishi * with a read/write mount and are protected from the 1050032dbb3bSRyusuke Konishi * cleaner. 105129619809SKoji Sato */ 105229619809SKoji Sato ret = -EBUSY; 1053032dbb3bSRyusuke Konishi else 105429619809SKoji Sato ret = nilfs_cpfile_clear_snapshot(cpfile, cno); 105529619809SKoji Sato return ret; 105629619809SKoji Sato case NILFS_SNAPSHOT: 105729619809SKoji Sato return nilfs_cpfile_set_snapshot(cpfile, cno); 105829619809SKoji Sato default: 105929619809SKoji Sato return -EINVAL; 106029619809SKoji Sato } 106129619809SKoji Sato } 106229619809SKoji Sato 106329619809SKoji Sato /** 106429619809SKoji Sato * nilfs_cpfile_get_stat - get checkpoint statistics 106529619809SKoji Sato * @cpfile: inode of checkpoint file 106664ead520SWang Hai * @cpstat: pointer to a structure of checkpoint statistics 106729619809SKoji Sato * 106829619809SKoji Sato * Description: nilfs_cpfile_get_stat() returns information about checkpoints. 106929619809SKoji Sato * 107029619809SKoji Sato * Return Value: On success, 0 is returned, and checkpoints information is 107164ead520SWang Hai * stored in the place pointed by @cpstat. On error, one of the following 107229619809SKoji Sato * negative error codes is returned. 107329619809SKoji Sato * 107429619809SKoji Sato * %-EIO - I/O error. 107529619809SKoji Sato * 107629619809SKoji Sato * %-ENOMEM - Insufficient amount of memory available. 107729619809SKoji Sato */ 107829619809SKoji Sato int nilfs_cpfile_get_stat(struct inode *cpfile, struct nilfs_cpstat *cpstat) 107929619809SKoji Sato { 108029619809SKoji Sato struct buffer_head *bh; 108129619809SKoji Sato struct nilfs_cpfile_header *header; 108229619809SKoji Sato void *kaddr; 108329619809SKoji Sato int ret; 108429619809SKoji Sato 108529619809SKoji Sato down_read(&NILFS_MDT(cpfile)->mi_sem); 108629619809SKoji Sato 108729619809SKoji Sato ret = nilfs_cpfile_get_header_block(cpfile, &bh); 108829619809SKoji Sato if (ret < 0) 108929619809SKoji Sato goto out_sem; 10905eccc067SRyusuke Konishi kaddr = kmap_local_page(bh->b_page); 109129619809SKoji Sato header = nilfs_cpfile_block_get_header(cpfile, bh, kaddr); 109229619809SKoji Sato cpstat->cs_cno = nilfs_mdt_cno(cpfile); 109329619809SKoji Sato cpstat->cs_ncps = le64_to_cpu(header->ch_ncheckpoints); 109429619809SKoji Sato cpstat->cs_nsss = le64_to_cpu(header->ch_nsnapshots); 10955eccc067SRyusuke Konishi kunmap_local(kaddr); 109629619809SKoji Sato brelse(bh); 109729619809SKoji Sato 109829619809SKoji Sato out_sem: 109929619809SKoji Sato up_read(&NILFS_MDT(cpfile)->mi_sem); 110029619809SKoji Sato return ret; 110129619809SKoji Sato } 110279739565SRyusuke Konishi 110379739565SRyusuke Konishi /** 1104f1e89c86SRyusuke Konishi * nilfs_cpfile_read - read or get cpfile inode 1105f1e89c86SRyusuke Konishi * @sb: super block instance 110679739565SRyusuke Konishi * @cpsize: size of a checkpoint entry 1107f1e89c86SRyusuke Konishi * @raw_inode: on-disk cpfile inode 1108f1e89c86SRyusuke Konishi * @inodep: buffer to store the inode 110979739565SRyusuke Konishi */ 1110f1e89c86SRyusuke Konishi int nilfs_cpfile_read(struct super_block *sb, size_t cpsize, 1111f1e89c86SRyusuke Konishi struct nilfs_inode *raw_inode, struct inode **inodep) 111279739565SRyusuke Konishi { 111379739565SRyusuke Konishi struct inode *cpfile; 1114f1e89c86SRyusuke Konishi int err; 111579739565SRyusuke Konishi 11160ec060d1SRyusuke Konishi if (cpsize > sb->s_blocksize) { 1117a1d0747aSJoe Perches nilfs_err(sb, "too large checkpoint size: %zu bytes", cpsize); 11180ec060d1SRyusuke Konishi return -EINVAL; 11190ec060d1SRyusuke Konishi } else if (cpsize < NILFS_MIN_CHECKPOINT_SIZE) { 1120a1d0747aSJoe Perches nilfs_err(sb, "too small checkpoint size: %zu bytes", cpsize); 11210ec060d1SRyusuke Konishi return -EINVAL; 11220ec060d1SRyusuke Konishi } 11230ec060d1SRyusuke Konishi 1124f1e89c86SRyusuke Konishi cpfile = nilfs_iget_locked(sb, NULL, NILFS_CPFILE_INO); 1125f1e89c86SRyusuke Konishi if (unlikely(!cpfile)) 1126f1e89c86SRyusuke Konishi return -ENOMEM; 1127f1e89c86SRyusuke Konishi if (!(cpfile->i_state & I_NEW)) 1128f1e89c86SRyusuke Konishi goto out; 1129f1e89c86SRyusuke Konishi 1130f1e89c86SRyusuke Konishi err = nilfs_mdt_init(cpfile, NILFS_MDT_GFP, 0); 1131f1e89c86SRyusuke Konishi if (err) 1132f1e89c86SRyusuke Konishi goto failed; 1133f1e89c86SRyusuke Konishi 113479739565SRyusuke Konishi nilfs_mdt_set_entry_size(cpfile, cpsize, 113579739565SRyusuke Konishi sizeof(struct nilfs_cpfile_header)); 1136f1e89c86SRyusuke Konishi 1137f1e89c86SRyusuke Konishi err = nilfs_read_inode_common(cpfile, raw_inode); 1138f1e89c86SRyusuke Konishi if (err) 1139f1e89c86SRyusuke Konishi goto failed; 1140f1e89c86SRyusuke Konishi 1141f1e89c86SRyusuke Konishi unlock_new_inode(cpfile); 1142f1e89c86SRyusuke Konishi out: 1143f1e89c86SRyusuke Konishi *inodep = cpfile; 1144f1e89c86SRyusuke Konishi return 0; 1145f1e89c86SRyusuke Konishi failed: 1146f1e89c86SRyusuke Konishi iget_failed(cpfile); 1147f1e89c86SRyusuke Konishi return err; 114879739565SRyusuke Konishi } 1149