/** * alloc_nilfs - allocate a nilfs object * @sb: super block instance * * Return: a pointer to the allocated nilfs object on success, or NULL on * failure.
*/ struct the_nilfs *alloc_nilfs(struct super_block *sb)
{ struct the_nilfs *nilfs;
nilfs = kzalloc(sizeof(*nilfs), GFP_KERNEL); if (!nilfs) return NULL;
/** * nilfs_store_log_cursor - load log cursor from a super block * @nilfs: nilfs object * @sbp: buffer storing super block to be read * * nilfs_store_log_cursor() reads the last position of the log * containing a super root from a given super block, and initializes * relevant information on the nilfs object preparatory for log * scanning and recovery. * * Return: 0 on success, or %-EINVAL if current segment number is out * of range.
*/ staticint nilfs_store_log_cursor(struct the_nilfs *nilfs, struct nilfs_super_block *sbp)
{ int ret = 0;
nilfs->ns_prev_seq = nilfs->ns_last_seq;
nilfs->ns_seg_seq = nilfs->ns_last_seq;
nilfs->ns_segnum =
nilfs_get_segnum_of_block(nilfs, nilfs->ns_last_pseg);
nilfs->ns_cno = nilfs->ns_last_cno + 1; if (nilfs->ns_segnum >= nilfs->ns_nsegments) {
nilfs_err(nilfs->ns_sb, "pointed segment number is out of range: segnum=%llu, nsegments=%lu",
(unsignedlonglong)nilfs->ns_segnum,
nilfs->ns_nsegments);
ret = -EINVAL;
} return ret;
}
/** * nilfs_get_blocksize - get block size from raw superblock data * @sb: super block instance * @sbp: superblock raw data buffer * @blocksize: place to store block size * * nilfs_get_blocksize() calculates the block size from the block size * exponent information written in @sbp and stores it in @blocksize, * or aborts with an error message if it's too large. * * Return: 0 on success, or %-EINVAL if the block size is too large.
*/ staticint nilfs_get_blocksize(struct super_block *sb, struct nilfs_super_block *sbp, int *blocksize)
{ unsignedint shift_bits = le32_to_cpu(sbp->s_log_block_size);
/** * load_nilfs - load and recover the nilfs * @nilfs: the_nilfs structure to be released * @sb: super block instance used to recover past segment * * load_nilfs() searches and load the latest super root, * attaches the last segment, and does recovery if needed. * The caller must call this exclusively for simultaneous mounts. * * Return: 0 on success, or one of the following negative error codes on * failure: * * %-EINVAL - No valid segment found. * * %-EIO - I/O error. * * %-ENOMEM - Insufficient memory available. * * %-EROFS - Read only device or RO compat mode (if recovery is required)
*/ int load_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
{ struct nilfs_recovery_info ri; unsignedint s_flags = sb->s_flags; int really_read_only = bdev_read_only(nilfs->ns_bdev); int valid_fs = nilfs_valid_fs(nilfs); int err;
if (!valid_fs) {
nilfs_warn(sb, "mounting unchecked fs"); if (s_flags & SB_RDONLY) {
nilfs_info(sb, "recovery required for readonly filesystem");
nilfs_info(sb, "write access will be enabled during recovery");
}
}
nilfs_init_recovery_info(&ri);
err = nilfs_search_super_root(nilfs, &ri); if (unlikely(err)) { struct nilfs_super_block **sbp = nilfs->ns_sbp; int blocksize;
if (err != -EINVAL) goto scan_error;
if (!nilfs_valid_sb(sbp[1])) {
nilfs_warn(sb, "unable to fall back to spare super block"); goto scan_error;
}
nilfs_info(sb, "trying rollback from an earlier position");
/* * restore super block with its spare and reconfigure * relevant states of the nilfs object.
*/
memcpy(sbp[0], sbp[1], nilfs->ns_sbsize);
nilfs->ns_crc_seed = le32_to_cpu(sbp[0]->s_crc_seed);
nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime);
/* verify consistency between two super blocks */
err = nilfs_get_blocksize(sb, sbp[0], &blocksize); if (err) goto scan_error;
if (blocksize != nilfs->ns_blocksize) {
nilfs_warn(sb, "blocksize differs between two super blocks (%d != %d)",
blocksize, nilfs->ns_blocksize);
err = -EINVAL; goto scan_error;
}
err = nilfs_store_log_cursor(nilfs, sbp[0]); if (err) goto scan_error;
/* drop clean flag to allow roll-forward and recovery */
nilfs->ns_mount_state &= ~NILFS_VALID_FS;
valid_fs = 0;
err = nilfs_search_super_root(nilfs, &ri); if (err) goto scan_error;
}
err = nilfs_load_super_root(nilfs, sb, ri.ri_super_root); if (unlikely(err)) {
nilfs_err(sb, "error %d while loading super root", err); goto failed;
}
err = nilfs_sysfs_create_device_group(sb); if (unlikely(err)) goto sysfs_error;
if (valid_fs) goto skip_recovery;
if (s_flags & SB_RDONLY) {
__u64 features;
if (nilfs_test_opt(nilfs, NORECOVERY)) {
nilfs_info(sb, "norecovery option specified, skipping roll-forward recovery"); goto skip_recovery;
}
features = le64_to_cpu(nilfs->ns_sbp[0]->s_feature_compat_ro) &
~NILFS_FEATURE_COMPAT_RO_SUPP; if (features) {
nilfs_err(sb, "couldn't proceed with recovery because of unsupported optional features (%llx)",
(unsignedlonglong)features);
err = -EROFS; goto failed_unload;
} if (really_read_only) {
nilfs_err(sb, "write access unavailable, cannot proceed");
err = -EROFS; goto failed_unload;
}
sb->s_flags &= ~SB_RDONLY;
} elseif (nilfs_test_opt(nilfs, NORECOVERY)) {
nilfs_err(sb, "recovery cancelled because norecovery option was specified for a read/write mount");
err = -EINVAL; goto failed_unload;
}
err = nilfs_salvage_orphan_logs(nilfs, sb, &ri); if (err) goto failed_unload;
down_write(&nilfs->ns_sem);
nilfs->ns_mount_state |= NILFS_VALID_FS; /* set "clean" flag */
err = nilfs_cleanup_super(sb);
up_write(&nilfs->ns_sem);
if (err) {
nilfs_err(sb, "error %d updating super block. recovery unfinished.",
err); goto failed_unload;
}
nilfs_info(sb, "recovery complete");
/** * nilfs_nrsvsegs - calculate the number of reserved segments * @nilfs: nilfs object * @nsegs: total number of segments * * Return: Number of reserved segments.
*/ unsignedlong nilfs_nrsvsegs(struct the_nilfs *nilfs, unsignedlong nsegs)
{ return max_t(unsignedlong, NILFS_MIN_NRSVSEGS,
DIV_ROUND_UP(nsegs * nilfs->ns_r_segments_percentage,
100));
}
/** * nilfs_max_segment_count - calculate the maximum number of segments * @nilfs: nilfs object * * Return: Maximum number of segments
*/ static u64 nilfs_max_segment_count(struct the_nilfs *nilfs)
{
u64 max_count = U64_MAX;
nblocks = sb_bdev_nr_blocks(nilfs->ns_sb); if (nblocks) {
u64 min_block_count = nsegments * nilfs->ns_blocks_per_segment; /* * To avoid failing to mount early device images without a * second superblock, exclude that block count from the * "min_block_count" calculation.
*/
if (nblocks < min_block_count) {
nilfs_err(nilfs->ns_sb, "total number of segment blocks %llu exceeds device size (%llu blocks)",
(unsignedlonglong)min_block_count,
(unsignedlonglong)nblocks); return -EINVAL;
}
}
/** * nilfs_sb2_bad_offset - check the location of the second superblock * @sbp: superblock raw data buffer * @offset: byte offset of second superblock calculated from device size * * nilfs_sb2_bad_offset() checks if the position on the second * superblock is valid or not based on the filesystem parameters * stored in @sbp. If @offset points to a location within the segment * area, or if the parameters themselves are not normal, it is * determined to be invalid. * * Return: true if invalid, false if valid.
*/ staticbool nilfs_sb2_bad_offset(struct nilfs_super_block *sbp, u64 offset)
{ unsignedint shift_bits = le32_to_cpu(sbp->s_log_block_size);
u32 blocks_per_segment = le32_to_cpu(sbp->s_blocks_per_segment);
u64 nsegments = le64_to_cpu(sbp->s_nsegments);
u64 index;
if (!sbp[0]) { if (!sbp[1]) {
nilfs_err(sb, "unable to read superblock"); return -EIO;
}
nilfs_warn(sb, "unable to read primary superblock (blocksize = %d)",
blocksize);
} elseif (!sbp[1]) {
nilfs_warn(sb, "unable to read secondary superblock (blocksize = %d)",
blocksize);
}
/* * Compare two super blocks and set 1 in swp if the secondary * super block is valid and newer. Otherwise, set 0 in swp.
*/
valid[0] = nilfs_valid_sb(sbp[0]);
valid[1] = nilfs_valid_sb(sbp[1]);
swp = valid[1] && (!valid[0] ||
le64_to_cpu(sbp[1]->s_last_cno) >
le64_to_cpu(sbp[0]->s_last_cno));
if (valid[swp] && nilfs_sb2_bad_offset(sbp[swp], sb2off)) {
brelse(sbh[1]);
sbh[1] = NULL;
sbp[1] = NULL;
valid[1] = 0;
swp = 0;
} if (!valid[swp]) {
nilfs_release_super_block(nilfs);
nilfs_err(sb, "couldn't find nilfs on the device"); return -EINVAL;
}
if (!valid[!swp])
nilfs_warn(sb, "broken superblock, retrying with spare superblock (blocksize = %d)",
blocksize); if (swp)
nilfs_swap_super_block(nilfs);
/* * Calculate the array index of the older superblock data. * If one has been dropped, set index 0 pointing to the remaining one, * otherwise set index 1 pointing to the old one (including if both * are the same). * * Divided case valid[0] valid[1] swp -> older * ------------------------------------------------------------- * Both SBs are invalid 0 0 N/A (Error) * SB1 is invalid 0 1 1 0 * SB2 is invalid 1 0 0 0 * SB2 is newer 1 1 1 0 * SB2 is older or the same 1 1 0 1
*/
older = valid[1] ^ swp;
/** * init_nilfs - initialize a NILFS instance. * @nilfs: the_nilfs structure * @sb: super block * * init_nilfs() performs common initialization per block device (e.g. * reading the super block, getting disk layout information, initializing * shared fields in the_nilfs). * * Return: 0 on success, or a negative error code on failure.
*/ int init_nilfs(struct the_nilfs *nilfs, struct super_block *sb)
{ struct nilfs_super_block *sbp; int blocksize; int err;
blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE); if (!blocksize) {
nilfs_err(sb, "unable to set blocksize");
err = -EINVAL; goto out;
}
err = nilfs_load_super_block(nilfs, sb, blocksize, &sbp); if (err) goto out;
err = nilfs_store_magic(sb, sbp); if (err) goto failed_sbh;
err = nilfs_check_feature_compatibility(sb, sbp); if (err) goto failed_sbh;
err = nilfs_get_blocksize(sb, sbp, &blocksize); if (err) goto failed_sbh;
if (blocksize < NILFS_MIN_BLOCK_SIZE) {
nilfs_err(sb, "couldn't mount because of unsupported filesystem blocksize %d",
blocksize);
err = -EINVAL; goto failed_sbh;
} if (sb->s_blocksize != blocksize) { int hw_blocksize = bdev_logical_block_size(sb->s_bdev);
if (blocksize < hw_blocksize) {
nilfs_err(sb, "blocksize %d too small for device (sector-size = %d)",
blocksize, hw_blocksize);
err = -EINVAL; goto failed_sbh;
}
nilfs_release_super_block(nilfs); if (!sb_set_blocksize(sb, blocksize)) {
nilfs_err(sb, "bad blocksize %d", blocksize);
err = -EINVAL; goto out;
}
err = nilfs_load_super_block(nilfs, sb, blocksize, &sbp); if (err) goto out; /* * Not to failed_sbh; sbh is released automatically * when reloading fails.
*/
}
nilfs->ns_blocksize_bits = sb->s_blocksize_bits;
nilfs->ns_blocksize = blocksize;
err = nilfs_store_disk_layout(nilfs, sbp); if (err) goto failed_sbh;
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.