/* block number from the beginning of the file */ staticunsignedlong
nilfs_cpfile_get_blkoff(conststruct inode *cpfile, __u64 cno)
{
__u64 tcno = cno + NILFS_MDT(cpfile)->mi_first_entry_offset - 1;
/** * nilfs_cpfile_checkpoint_offset - calculate the byte offset of a checkpoint * entry in the folio containing it * @cpfile: checkpoint file inode * @cno: checkpoint number * @bh: buffer head of block containing checkpoint indexed by @cno * * Return: Byte offset in the folio of the checkpoint specified by @cno.
*/ static size_t nilfs_cpfile_checkpoint_offset(conststruct inode *cpfile,
__u64 cno, struct buffer_head *bh)
{ return offset_in_folio(bh->b_folio, bh->b_data) +
nilfs_cpfile_get_offset(cpfile, cno) *
NILFS_MDT(cpfile)->mi_entry_size;
}
/** * nilfs_cpfile_cp_snapshot_list_offset - calculate the byte offset of a * checkpoint snapshot list in the folio * containing it * @cpfile: checkpoint file inode * @cno: checkpoint number * @bh: buffer head of block containing checkpoint indexed by @cno * * Return: Byte offset in the folio of the checkpoint snapshot list specified * by @cno.
*/ static size_t nilfs_cpfile_cp_snapshot_list_offset(conststruct inode *cpfile,
__u64 cno, struct buffer_head *bh)
{ return nilfs_cpfile_checkpoint_offset(cpfile, cno, bh) +
offsetof(struct nilfs_checkpoint, cp_snapshot_list);
}
/** * nilfs_cpfile_ch_snapshot_list_offset - calculate the byte offset of the * snapshot list in the header * * Return: Byte offset in the folio of the checkpoint snapshot list
*/ static size_t nilfs_cpfile_ch_snapshot_list_offset(void)
{ return offsetof(struct nilfs_cpfile_header, ch_snapshot_list);
}
/** * nilfs_cpfile_find_checkpoint_block - find and get a buffer on cpfile * @cpfile: inode of cpfile * @start_cno: start checkpoint number (inclusive) * @end_cno: end checkpoint number (inclusive) * @cnop: place to store the next checkpoint number * @bhp: place to store a pointer to buffer_head struct * * Return: 0 on success, or one of the following negative error codes on * failure: * * %-EIO - I/O error (including metadata corruption). * * %-ENOENT - no block exists in the range. * * %-ENOMEM - Insufficient memory available.
*/ staticint nilfs_cpfile_find_checkpoint_block(struct inode *cpfile,
__u64 start_cno, __u64 end_cno,
__u64 *cnop, struct buffer_head **bhp)
{ unsignedlong start, end, blkoff; int ret;
if (unlikely(start_cno > end_cno)) return -ENOENT;
start = nilfs_cpfile_get_blkoff(cpfile, start_cno);
end = nilfs_cpfile_get_blkoff(cpfile, end_cno);
/** * nilfs_cpfile_read_checkpoint - read a checkpoint entry in cpfile * @cpfile: checkpoint file inode * @cno: number of checkpoint entry to read * @root: nilfs root object * @ifile: ifile's inode to read and attach to @root * * This function imports checkpoint information from the checkpoint file and * stores it to the inode file given by @ifile and the nilfs root object * given by @root. * * Return: 0 on success, or one of the following negative error codes on * failure: * * %-EINVAL - Invalid checkpoint. * * %-ENOMEM - Insufficient memory available. * * %-EIO - I/O error (including metadata corruption).
*/ int nilfs_cpfile_read_checkpoint(struct inode *cpfile, __u64 cno, struct nilfs_root *root, struct inode *ifile)
{ struct buffer_head *cp_bh; struct nilfs_checkpoint *cp;
size_t offset; int ret;
if (cno < 1 || cno > nilfs_mdt_cno(cpfile)) return -EINVAL;
down_read(&NILFS_MDT(cpfile)->mi_sem);
ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); if (unlikely(ret < 0)) { if (ret == -ENOENT)
ret = -EINVAL; goto out_sem;
}
offset = nilfs_cpfile_checkpoint_offset(cpfile, cno, cp_bh);
cp = kmap_local_folio(cp_bh->b_folio, offset); if (nilfs_checkpoint_invalid(cp)) {
ret = -EINVAL; goto put_cp;
}
ret = nilfs_read_inode_common(ifile, &cp->cp_ifile_inode); if (unlikely(ret)) { /* * Since this inode is on a checkpoint entry, treat errors * as metadata corruption.
*/
nilfs_err(cpfile->i_sb, "ifile inode (checkpoint number=%llu) corrupted",
(unsignedlonglong)cno);
ret = -EIO; goto put_cp;
}
/** * nilfs_cpfile_create_checkpoint - create a checkpoint entry on cpfile * @cpfile: checkpoint file inode * @cno: number of checkpoint to set up * * This function creates a checkpoint with the number specified by @cno on * cpfile. If the specified checkpoint entry already exists due to a past * failure, it will be reused without returning an error. * In either case, the buffer of the block containing the checkpoint entry * and the cpfile inode are made dirty for inclusion in the write log. * * Return: 0 on success, or one of the following negative error codes on * failure: * * %-ENOMEM - Insufficient memory available. * * %-EIO - I/O error (including metadata corruption). * * %-EROFS - Read only filesystem
*/ int nilfs_cpfile_create_checkpoint(struct inode *cpfile, __u64 cno)
{ struct buffer_head *header_bh, *cp_bh; struct nilfs_cpfile_header *header; struct nilfs_checkpoint *cp;
size_t offset; int ret;
if (WARN_ON_ONCE(cno < 1)) return -EIO;
down_write(&NILFS_MDT(cpfile)->mi_sem);
ret = nilfs_cpfile_get_header_block(cpfile, &header_bh); if (unlikely(ret < 0)) goto out_sem;
ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 1, &cp_bh); if (unlikely(ret < 0)) goto out_header;
offset = nilfs_cpfile_checkpoint_offset(cpfile, cno, cp_bh);
cp = kmap_local_folio(cp_bh->b_folio, offset); if (nilfs_checkpoint_invalid(cp)) { /* a newly-created checkpoint */
nilfs_checkpoint_clear_invalid(cp);
kunmap_local(cp); if (!nilfs_cpfile_is_in_first(cpfile, cno))
nilfs_cpfile_block_add_valid_checkpoints(cpfile, cp_bh,
1);
/** * nilfs_cpfile_finalize_checkpoint - fill in a checkpoint entry in cpfile * @cpfile: checkpoint file inode * @cno: checkpoint number * @root: nilfs root object * @blkinc: number of blocks added by this checkpoint * @ctime: checkpoint creation time * @minor: minor checkpoint flag * * This function completes the checkpoint entry numbered by @cno in the * cpfile with the data given by the arguments @root, @blkinc, @ctime, and * @minor. * * Return: 0 on success, or one of the following negative error codes on * failure: * * %-ENOMEM - Insufficient memory available. * * %-EIO - I/O error (including metadata corruption).
*/ int nilfs_cpfile_finalize_checkpoint(struct inode *cpfile, __u64 cno, struct nilfs_root *root, __u64 blkinc,
time64_t ctime, bool minor)
{ struct buffer_head *cp_bh; struct nilfs_checkpoint *cp;
size_t offset; int ret;
if (WARN_ON_ONCE(cno < 1)) return -EIO;
down_write(&NILFS_MDT(cpfile)->mi_sem);
ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &cp_bh); if (unlikely(ret < 0)) { if (ret == -ENOENT) goto error; goto out_sem;
}
count = nilfs_cpfile_block_sub_valid_checkpoints(cpfile, cp_bh,
nicps);
brelse(cp_bh); if (count) continue;
/* Delete the block if there are no more valid checkpoints */
ret = nilfs_cpfile_delete_checkpoint_block(cpfile, cno); if (unlikely(ret)) {
nilfs_err(cpfile->i_sb, "error %d deleting checkpoint block", ret); break;
}
}
/** * nilfs_cpfile_get_cpinfo - get information on checkpoints * @cpfile: checkpoint file inode * @cnop: place to pass a starting checkpoint number and receive a * checkpoint number to continue the search * @mode: mode of checkpoints that the caller wants to retrieve * @buf: buffer for storing checkpoints' information * @cisz: byte size of one checkpoint info item in array * @nci: number of checkpoint info items to retrieve * * nilfs_cpfile_get_cpinfo() searches for checkpoints in @mode state * starting from the checkpoint number stored in @cnop, and stores * information about found checkpoints in @buf. * The buffer pointed to by @buf must be large enough to store information * for @nci checkpoints. If at least one checkpoint information is * successfully retrieved, @cnop is updated to point to the checkpoint * number to continue searching. * * Return: Count of checkpoint info items stored in the output buffer on * success, or one of the following negative error codes on failure: * * %-EINVAL - Invalid checkpoint mode. * * %-ENOMEM - Insufficient memory available. * * %-EIO - I/O error (including metadata corruption). * * %-ENOENT - Invalid checkpoint number specified.
*/
/* Update the list entry for the next snapshot */
list = kmap_local_folio(curr_bh->b_folio, curr_list_offset);
list->ssl_prev = cpu_to_le64(cno);
kunmap_local(list);
/* Update the checkpoint being changed to a snapshot */
offset = nilfs_cpfile_checkpoint_offset(cpfile, cno, cp_bh);
cp = kmap_local_folio(cp_bh->b_folio, offset);
cp->cp_snapshot_list.ssl_next = cpu_to_le64(curr);
cp->cp_snapshot_list.ssl_prev = cpu_to_le64(prev);
nilfs_checkpoint_set_snapshot(cp);
kunmap_local(cp);
/* Update the list entry for the previous snapshot */
list = kmap_local_folio(prev_bh->b_folio, prev_list_offset);
list->ssl_next = cpu_to_le64(cno);
kunmap_local(list);
/* Update the statistics in the header */
header = kmap_local_folio(header_bh->b_folio, 0);
le64_add_cpu(&header->ch_nsnapshots, 1);
kunmap_local(header);
/* Update the list entry for the next snapshot */
list = kmap_local_folio(next_bh->b_folio, next_list_offset);
list->ssl_prev = cpu_to_le64(prev);
kunmap_local(list);
/* Update the list entry for the previous snapshot */
list = kmap_local_folio(prev_bh->b_folio, prev_list_offset);
list->ssl_next = cpu_to_le64(next);
kunmap_local(list);
/* Update the snapshot being changed back to a plain checkpoint */
cp = kmap_local_folio(cp_bh->b_folio, offset);
cp->cp_snapshot_list.ssl_next = cpu_to_le64(0);
cp->cp_snapshot_list.ssl_prev = cpu_to_le64(0);
nilfs_checkpoint_clear_snapshot(cp);
kunmap_local(cp);
/* Update the statistics in the header */
header = kmap_local_folio(header_bh->b_folio, 0);
le64_add_cpu(&header->ch_nsnapshots, -1);
kunmap_local(header);
/** * nilfs_cpfile_is_snapshot - determine if checkpoint is a snapshot * @cpfile: inode of checkpoint file * @cno: checkpoint number * * Return: 1 if the checkpoint specified by @cno is a snapshot, 0 if not, or * one of the following negative error codes on failure: * * %-EIO - I/O error (including metadata corruption). * * %-ENOENT - No such checkpoint. * * %-ENOMEM - Insufficient memory available.
*/ int nilfs_cpfile_is_snapshot(struct inode *cpfile, __u64 cno)
{ struct buffer_head *bh; struct nilfs_checkpoint *cp;
size_t offset; int ret;
/* * CP number is invalid if it's zero or larger than the * largest existing one.
*/ if (cno == 0 || cno >= nilfs_mdt_cno(cpfile)) return -ENOENT;
down_read(&NILFS_MDT(cpfile)->mi_sem);
ret = nilfs_cpfile_get_checkpoint_block(cpfile, cno, 0, &bh); if (ret < 0) goto out;
offset = nilfs_cpfile_checkpoint_offset(cpfile, cno, bh);
cp = kmap_local_folio(bh->b_folio, offset); if (nilfs_checkpoint_invalid(cp))
ret = -ENOENT; else
ret = nilfs_checkpoint_snapshot(cp);
kunmap_local(cp);
brelse(bh);
/** * nilfs_cpfile_change_cpmode - change checkpoint mode * @cpfile: inode of checkpoint file * @cno: checkpoint number * @mode: mode of checkpoint * * Description: nilfs_change_cpmode() changes the mode of the checkpoint * specified by @cno. The mode @mode is NILFS_CHECKPOINT or NILFS_SNAPSHOT. * * Return: 0 on success, or one of the following negative error codes on * failure: * * %-EIO - I/O error (including metadata corruption). * * %-ENOENT - No such checkpoint. * * %-ENOMEM - Insufficient memory available.
*/ int nilfs_cpfile_change_cpmode(struct inode *cpfile, __u64 cno, int mode)
{ int ret;
switch (mode) { case NILFS_CHECKPOINT: if (nilfs_checkpoint_is_mounted(cpfile->i_sb, cno)) /* * Current implementation does not have to protect * plain read-only mounts since they are exclusive * with a read/write mount and are protected from the * cleaner.
*/
ret = -EBUSY; else
ret = nilfs_cpfile_clear_snapshot(cpfile, cno); return ret; case NILFS_SNAPSHOT: return nilfs_cpfile_set_snapshot(cpfile, cno); default: return -EINVAL;
}
}
/** * nilfs_cpfile_get_stat - get checkpoint statistics * @cpfile: inode of checkpoint file * @cpstat: pointer to a structure of checkpoint statistics * * Description: nilfs_cpfile_get_stat() returns information about checkpoints. * The checkpoint statistics are stored in the location pointed to by @cpstat. * * Return: 0 on success, or one of the following negative error codes on * failure: * * %-EIO - I/O error (including metadata corruption). * * %-ENOMEM - Insufficient memory available.
*/ int nilfs_cpfile_get_stat(struct inode *cpfile, struct nilfs_cpstat *cpstat)
{ struct buffer_head *bh; struct nilfs_cpfile_header *header; int ret;
/** * nilfs_cpfile_read - read or get cpfile inode * @sb: super block instance * @cpsize: size of a checkpoint entry * @raw_inode: on-disk cpfile inode * @inodep: buffer to store the inode * * Return: 0 on success, or a negative error code on failure.
*/ int nilfs_cpfile_read(struct super_block *sb, size_t cpsize, struct nilfs_inode *raw_inode, struct inode **inodep)
{ struct inode *cpfile; int err;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.