/* * Clear the MMP usage in the filesystem. If this function returns an * error EXT2_ET_MMP_CHANGE_ABORT it means the filesystem was modified * by some other process while in use, and changes should be dropped, or * risk filesystem corruption. */ errcode_t ext2fs_mmp_stop(ext2_filsys fs) { struct mmp_struct *mmp, *mmp_cmp; errcode_t retval = 0; if (!(fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) || !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP)) goto mmp_error; retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf); if (retval) goto mmp_error; /* Check if the MMP block is not changed. */ mmp = fs->mmp_buf; mmp_cmp = fs->mmp_cmp; if (memcmp(mmp, mmp_cmp, sizeof(*mmp_cmp))) { retval = EXT2_ET_MMP_CHANGE_ABORT; goto mmp_error; } mmp_cmp->mmp_seq = EXT4_MMP_SEQ_CLEAN; retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_cmp); mmp_error: if (fs->mmp_fd > 0) { close(fs->mmp_fd); fs->mmp_fd = -1; } return retval; }
/* * Update the on-disk mmp buffer, after checking that it hasn't been changed. */ errcode_t ext2fs_mmp_update(ext2_filsys fs) { struct mmp_struct *mmp, *mmp_cmp; struct timeval tv; errcode_t retval = 0; if (!(fs->super->s_feature_incompat & EXT4_FEATURE_INCOMPAT_MMP) || !(fs->flags & EXT2_FLAG_RW) || (fs->flags & EXT2_FLAG_SKIP_MMP)) return 0; gettimeofday(&tv, 0); if (tv.tv_sec - fs->mmp_last_written < EXT2_MIN_MMP_UPDATE_INTERVAL) return 0; retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, NULL); if (retval) goto mmp_error; mmp = fs->mmp_buf; mmp_cmp = fs->mmp_cmp; if (memcmp(mmp, mmp_cmp, sizeof(*mmp_cmp))) return EXT2_ET_MMP_CHANGE_ABORT; mmp->mmp_time = tv.tv_sec; mmp->mmp_seq = EXT4_MMP_SEQ_FSCK; retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_buf); mmp_error: return retval; }
void do_set_mmp_value(int argc, char *argv[]) { const char *usage = "<field> <value>\n" "\t\"set_mmp_value -l\" will list the names of " "MMP fields\n\twhich can be set."; static struct field_set_info *smmp; struct mmp_struct *mmp_s; errcode_t retval; if (argc == 2 && strcmp(argv[1], "-l") == 0) { print_possible_fields(mmp_fields); return; } if (current_fs->super->s_mmp_block == 0) { com_err(argv[0], 0, "no MMP block allocated\n"); return; } if (common_args_process(argc, argv, 2, 3, "set_mmp_value", usage, CHECK_FS_RW)) return; mmp_s = current_fs->mmp_buf; if (mmp_s == NULL) { retval = ext2fs_get_mem(current_fs->blocksize, &mmp_s); if (retval) { com_err(argv[0], retval, "allocating MMP buffer\n"); return; } retval = ext2fs_mmp_read(current_fs, current_fs->super->s_mmp_block, mmp_s); if (retval) { com_err(argv[0], retval, "reading MMP block %llu.\n", (long long)current_fs->super->s_mmp_block); ext2fs_free_mem(mmp_s); return; } current_fs->mmp_buf = mmp_s; } smmp = find_field(mmp_fields, argv[1]); if (smmp == 0) { com_err(argv[0], 0, "invalid field specifier: %s", argv[1]); return; } set_mmp = *mmp_s; if (smmp->func(smmp, argv[1], argv[2]) == 0) { ext2fs_mmp_write(current_fs, current_fs->super->s_mmp_block, &set_mmp); *mmp_s = set_mmp; } }
/* * Make sure that the fs is not mounted or being fsck'ed while opening the fs. */ errcode_t ext2fs_mmp_start(ext2_filsys fs) { struct mmp_struct *mmp_s; unsigned seq; unsigned int mmp_check_interval; errcode_t retval = 0; if (fs->mmp_buf == NULL) { retval = ext2fs_get_mem(fs->blocksize, &fs->mmp_buf); if (retval) goto mmp_error; } retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf); if (retval) goto mmp_error; mmp_s = fs->mmp_buf; mmp_check_interval = fs->super->s_mmp_update_interval; if (mmp_check_interval < EXT4_MMP_MIN_CHECK_INTERVAL) mmp_check_interval = EXT4_MMP_MIN_CHECK_INTERVAL; seq = mmp_s->mmp_seq; if (seq == EXT4_MMP_SEQ_CLEAN) goto clean_seq; if (seq == EXT4_MMP_SEQ_FSCK) { retval = EXT2_ET_MMP_FSCK_ON; goto mmp_error; } if (seq > EXT4_MMP_SEQ_FSCK) { retval = EXT2_ET_MMP_UNKNOWN_SEQ; goto mmp_error; } /* * If check_interval in MMP block is larger, use that instead of * check_interval from the superblock. */ if (mmp_s->mmp_check_interval > mmp_check_interval) mmp_check_interval = mmp_s->mmp_check_interval; //sleep(2 * mmp_check_interval + 1); retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf); if (retval) goto mmp_error; if (seq != mmp_s->mmp_seq) { retval = EXT2_ET_MMP_FAILED; goto mmp_error; } clean_seq: if (!(fs->flags & EXT2_FLAG_RW)) goto mmp_error; mmp_s->mmp_seq = seq = ext2fs_mmp_new_seq(); #if (0 && (_BSD_SOURCE || _XOPEN_SOURCE >= 500)) gethostname(mmp_s->mmp_nodename, sizeof(mmp_s->mmp_nodename)); #else strcpy(mmp_s->mmp_nodename, "unknown host"); #endif strncpy(mmp_s->mmp_bdevname, fs->device_name, sizeof(mmp_s->mmp_bdevname)); retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_buf); if (retval) goto mmp_error; //sleep(2 * mmp_check_interval + 1); retval = ext2fs_mmp_read(fs, fs->super->s_mmp_block, fs->mmp_buf); if (retval) goto mmp_error; if (seq != mmp_s->mmp_seq) { retval = EXT2_ET_MMP_FAILED; goto mmp_error; } mmp_s->mmp_seq = EXT4_MMP_SEQ_FSCK; retval = ext2fs_mmp_write(fs, fs->super->s_mmp_block, fs->mmp_buf); if (retval) goto mmp_error; return 0; mmp_error: return retval; }