Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4d26b266 authored by Keun-young Park's avatar Keun-young Park
Browse files

run e2fsck -f selectively with mount retry

- Do not use -f if it was cleanly shutdown.
- For unclean shutdown or other operation failures like
  mount, tune2fs failure, run full check.
- Still old image will run full check once in 5 reboots
  while new image will not run full check unless something
  fails.
- Add retry for final mount. If mount fails once, run full fsck
  once and try again.

bug: 32246772
bug: 35366616
Test: many reboots

(cherry picked from commit 40db04d6)

Change-Id: If312d91e09aca0648dd926e26a3d1e5f7ddedb46
parent 0af7ee4a
Loading
Loading
Loading
Loading
+84 −63
Original line number Diff line number Diff line
@@ -128,18 +128,20 @@ static void log_fs_stat(const char* blk_device, int fs_stat)
    }
}

static bool should_force_check(int fs_stat) {
    return fs_stat & (FS_STAT_E2FSCK_F_ALWAYS | FS_STAT_UNCLEAN_SHUTDOWN | FS_STAT_QUOTA_ENABLED |
                      FS_STAT_TUNE2FS_FAILED | FS_STAT_RO_MOUNT_FAILED | FS_STAT_RO_UNMOUNT_FAILED |
                      FS_STAT_FULL_MOUNT_FAILED | FS_STAT_E2FSCK_FAILED);
}

static void check_fs(const char *blk_device, char *fs_type, char *target, int *fs_stat)
{
    int status;
    int ret;
    long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
    char tmpmnt_opts[64] = "errors=remount-ro";
    const char *e2fsck_argv[] = {
        E2FSCK_BIN,
        "-f",
        "-y",
        blk_device
    };
    const char* e2fsck_argv[] = {E2FSCK_BIN, "-y", blk_device};
    const char* e2fsck_forced_argv[] = {E2FSCK_BIN, "-f", "-y", blk_device};

    /* Check for the types of filesystems we know how to check */
    if (!strcmp(fs_type, "ext2") || !strcmp(fs_type, "ext3") || !strcmp(fs_type, "ext4")) {
@@ -159,33 +161,36 @@ static void check_fs(const char *blk_device, char *fs_type, char *target, int *f
         * filesytsem due to an error, e2fsck is still run to do a full check
         * fix the filesystem.
         */
        if (!(*fs_stat & FS_STAT_FULL_MOUNT_FAILED)) {  // already tried if full mount failed
            errno = 0;
            if (!strcmp(fs_type, "ext4")) {
                // This option is only valid with ext4
                strlcat(tmpmnt_opts, ",nomblk_io_submit", sizeof(tmpmnt_opts));
            }
            ret = mount(blk_device, target, fs_type, tmpmnt_flags, tmpmnt_opts);
        PINFO << __FUNCTION__ << "(): mount(" << blk_device <<  "," << target
              << "," << fs_type << ")=" << ret;
            PINFO << __FUNCTION__ << "(): mount(" << blk_device << "," << target << "," << fs_type
                  << ")=" << ret;
            if (!ret) {
            int i;
            for (i = 0; i < 5; i++) {
                // Try to umount 5 times before continuing on.
                // Should we try rebooting if all attempts fail?
                int result = umount(target);
                if (result == 0) {
                    LINFO << __FUNCTION__ << "(): unmount(" << target
                          << ") succeeded";
                bool umounted = false;
                int retry_count = 5;
                while (retry_count-- > 0) {
                    umounted = umount(target) == 0;
                    if (umounted) {
                        LINFO << __FUNCTION__ << "(): unmount(" << target << ") succeeded";
                        break;
                    }
                    PERROR << __FUNCTION__ << "(): umount(" << target << ") failed";
                    if (retry_count) sleep(1);
                }
                if (!umounted) {
                    // boot may fail but continue and leave it to later stage for now.
                    PERROR << __FUNCTION__ << "(): umount(" << target << ") timed out";
                    *fs_stat |= FS_STAT_RO_UNMOUNT_FAILED;
                PERROR << __FUNCTION__ << "(): umount(" << target << ")="
                       << result;
                sleep(1);
                }
            } else {
                *fs_stat |= FS_STAT_RO_MOUNT_FAILED;
            }
        }

        /*
         * Some system images do not have e2fsck for licensing reasons
@@ -196,14 +201,15 @@ static void check_fs(const char *blk_device, char *fs_type, char *target, int *f
                  << " (executable not in system image)";
        } else {
            LINFO << "Running " << E2FSCK_BIN << " on " << blk_device;

            *fs_stat |= FS_STAT_E2FSCK_F_ALWAYS;
            ret = android_fork_execvp_ext(ARRAY_SIZE(e2fsck_argv),
                                          const_cast<char **>(e2fsck_argv),
                                          &status, true, LOG_KLOG | LOG_FILE,
                                          true,
                                          const_cast<char *>(FSCK_LOG_FILE),
                                          NULL, 0);
            if (should_force_check(*fs_stat)) {
                ret = android_fork_execvp_ext(
                    ARRAY_SIZE(e2fsck_forced_argv), const_cast<char**>(e2fsck_forced_argv), &status,
                    true, LOG_KLOG | LOG_FILE, true, const_cast<char*>(FSCK_LOG_FILE), NULL, 0);
            } else {
                ret = android_fork_execvp_ext(
                    ARRAY_SIZE(e2fsck_argv), const_cast<char**>(e2fsck_argv), &status, true,
                    LOG_KLOG | LOG_FILE, true, const_cast<char*>(FSCK_LOG_FILE), NULL, 0);
            }

            if (ret < 0) {
                /* No need to check for error in fork, we can't really handle it now */
@@ -574,22 +580,32 @@ static int mount_with_alternatives(struct fstab *fstab, int start_idx, int *end_
                                 &fstab->recs[i], &fs_stat);
            }

            if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point, &fstab->recs[i])) {
            int retry_count = 2;
            while (retry_count-- > 0) {
                if (!__mount(fstab->recs[i].blk_device, fstab->recs[i].mount_point,
                             &fstab->recs[i])) {
                    *attempted_idx = i;
                    mounted = 1;
                    if (i != start_idx) {
                    LERROR << __FUNCTION__ << "(): Mounted "
                           << fstab->recs[i].blk_device << " on "
                           << fstab->recs[i].mount_point << " with fs_type="
                           << fstab->recs[i].fs_type << " instead of "
                        LERROR << __FUNCTION__ << "(): Mounted " << fstab->recs[i].blk_device
                               << " on " << fstab->recs[i].mount_point
                               << " with fs_type=" << fstab->recs[i].fs_type << " instead of "
                               << fstab->recs[start_idx].fs_type;
                    }
                    fs_stat &= ~FS_STAT_FULL_MOUNT_FAILED;
                    mount_errno = 0;
                    break;
                } else {
                    if (retry_count <= 0) break;  // run check_fs only once
                    fs_stat |= FS_STAT_FULL_MOUNT_FAILED;
                    /* back up the first errno for crypto decisions */
                    if (mount_errno == 0) {
                        mount_errno = errno;
                    }
                    // retry after fsck
                    check_fs(fstab->recs[i].blk_device, fstab->recs[i].fs_type,
                             fstab->recs[i].mount_point, &fs_stat);
                }
            }
            log_fs_stat(fstab->recs[i].blk_device, fs_stat);
    }
@@ -1074,17 +1090,22 @@ int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
        } else {
            m = fstab->recs[i].mount_point;
        }
        if (__mount(n_blk_device, m, &fstab->recs[i])) {
        int retry_count = 2;
        while (retry_count-- > 0) {
            if (!__mount(n_blk_device, m, &fstab->recs[i])) {
                ret = 0;
                fs_stat &= ~FS_STAT_FULL_MOUNT_FAILED;
                goto out;
            } else {
                if (retry_count <= 0) break;  // run check_fs only once
                if (!first_mount_errno) first_mount_errno = errno;
                mount_errors++;
                fs_stat |= FS_STAT_FULL_MOUNT_FAILED;
            log_fs_stat(fstab->recs[i].blk_device, fs_stat);
            continue;
        } else {
            ret = 0;
            log_fs_stat(fstab->recs[i].blk_device, fs_stat);
            goto out;
                // try again after fsck
                check_fs(n_blk_device, fstab->recs[i].fs_type, fstab->recs[i].mount_point, &fs_stat);
            }
        }
        log_fs_stat(fstab->recs[i].blk_device, fs_stat);
    }
    if (mount_errors) {
        PERROR << "Cannot mount filesystem on " << n_blk_device