commit eb9181b33bdda2e1ce81094d77913f7b68e26156 Author: Felix Fietkau Date: Sun Mar 22 15:59:33 2015 +0100 mount_root: keep track of overlay initialization state (via xattr) Remove all files (except sysupgrade.tgz) if /etc/init.d/done was not called Signed-off-by: Felix Fietkau diff --git a/jffs2reset.c b/jffs2reset.c index c9d4f5f..1080883 100644 --- a/jffs2reset.c +++ b/jffs2reset.c @@ -62,6 +62,7 @@ jffs2_reset(int argc, char **argv) mp = find_mount_point(v->blk, 1); if (mp) { ULOG_INFO("%s is mounted as %s, only erasing files\n", v->blk, mp); + fs_state_set("/overlay", FS_STATE_PENDING); overlay_delete(mp, false); mount(mp, "/", NULL, MS_REMOUNT, 0); } else { diff --git a/libfstools/libfstools.h b/libfstools/libfstools.h index 1d41eea..31d9f9e 100644 --- a/libfstools/libfstools.h +++ b/libfstools/libfstools.h @@ -28,6 +28,13 @@ enum { FS_UBIFS, }; +enum fs_state { + FS_STATE_UNKNOWN, + FS_STATE_PENDING, + FS_STATE_READY, + __FS_STATE_LAST = FS_STATE_READY, +}; + extern char const *extroot_prefix; extern int mount_extroot(void); extern int mount_snapshot(struct volume *v); @@ -50,4 +57,7 @@ extern void foreachdir(const char *dir, int (*cb)(const char*)); extern void overlay_delete(const char *dir, bool keep_sysupgrade); +enum fs_state fs_state_get(const char *dir); +int fs_state_set(const char *dir, enum fs_state state); + #endif diff --git a/libfstools/overlay.c b/libfstools/overlay.c index 7c9b480..3269a52 100644 --- a/libfstools/overlay.c +++ b/libfstools/overlay.c @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -34,6 +35,18 @@ static bool keep_sysupgrade; +static ssize_t +fs_getxattr(const char *path, const char *name, void *value, size_t size) +{ + return syscall(__NR_getxattr, path, name, value, size); +} + +static ssize_t +fs_setxattr(const char *path, const char *name, const void *value, size_t size, int flags) +{ + return syscall(__NR_setxattr, path, name, value, size, flags); +} + static int handle_rmdir(const char *dir) { @@ -235,7 +248,13 @@ jffs2_switch(struct volume *v) } break; } - return ret; + + if (ret) + return ret; + + sync(); + fs_state_set("/overlay", FS_STATE_READY); + return 0; } static int overlay_mount_fs(struct volume *v) @@ -266,6 +285,28 @@ static int overlay_mount_fs(struct volume *v) return -1; } +enum fs_state fs_state_get(const char *dir) +{ + uint32_t val; + + if (fs_getxattr(dir, "user.fs_state", &val, sizeof(val)) != sizeof(val)) + return FS_STATE_UNKNOWN; + + if (val > __FS_STATE_LAST) + return FS_STATE_UNKNOWN; + + return val; +} + + +int fs_state_set(const char *dir, enum fs_state state) +{ + uint32_t val = state; + + return fs_setxattr(dir, "user.fs_state", &val, sizeof(val), 0); +} + + int mount_overlay(struct volume *v) { char *mp; @@ -287,6 +328,21 @@ int mount_overlay(struct volume *v) return 0; } + switch(fs_state_get("/tmp/overlay")) { + case FS_STATE_UNKNOWN: + fs_state_set("/tmp/overlay", FS_STATE_PENDING); + if (fs_state_get("/tmp/overlay") != FS_STATE_PENDING) { + ULOG_ERR("unable to set filesystem state\n"); + break; + } + case FS_STATE_PENDING: + ULOG_INFO("overlay filesystem has not been fully initialized yet\n"); + overlay_delete("/tmp/overlay", true); + break; + case FS_STATE_READY: + break; + } + ULOG_INFO("switching to jffs2 overlay\n"); if (mount_move("/tmp", "", "/overlay") || fopivot("/overlay", "/rom")) { ULOG_ERR("switching to jffs2 failed - fallback to ramoverlay\n"); diff --git a/mount_root.c b/mount_root.c index bfbe217..7b69c7f 100644 --- a/mount_root.c +++ b/mount_root.c @@ -103,6 +103,11 @@ done(int argc, char *argv[1]) case FS_NONE: case FS_DEADCODE: return jffs2_switch(v); + + case FS_JFFS2: + case FS_UBIFS: + fs_state_set("/overlay", FS_STATE_READY); + break; } return 0; commit aa59a26581d5350ef065854bd0b8a86de910700b Author: Felix Fietkau Date: Sun Mar 22 14:11:39 2015 +0100 overlay: call volume_init() before mount Signed-off-by: Felix Fietkau diff --git a/libfstools/overlay.c b/libfstools/overlay.c index c535693..7c9b480 100644 --- a/libfstools/overlay.c +++ b/libfstools/overlay.c @@ -255,14 +255,14 @@ static int overlay_mount_fs(struct volume *v) break; } + volume_init(v); + if (mount(v->blk, "/tmp/overlay", fstype, MS_NOATIME, NULL)) { ULOG_ERR("failed to mount -t %s %s /tmp/overlay: %s\n", fstype, v->blk, strerror(errno)); return -1; } - volume_init(v); - return -1; } commit 2d6bccbb70ce2f8195aad348c653c4c13f21c90c Author: Felix Fietkau Date: Sun Mar 22 14:08:27 2015 +0100 overlay: create a common function for deleting all overlay data (optionally excluding sysupgrade.tgz) Signed-off-by: Felix Fietkau diff --git a/jffs2reset.c b/jffs2reset.c index 6beb81e..c9d4f5f 100644 --- a/jffs2reset.c +++ b/jffs2reset.c @@ -28,33 +28,6 @@ #include "libfstools/volume.h" static int -handle_rmdir(const char *dir) -{ - struct dirent *dt; - struct stat st; - DIR *d; - int fd; - - d = opendir(dir); - if (!d) - return -1; - - fd = dirfd(d); - - while ((dt = readdir(d)) != NULL) { - if (fstatat(fd, dt->d_name, &st, AT_SYMLINK_NOFOLLOW) || S_ISDIR(st.st_mode)) - continue; - - unlinkat(fd, dt->d_name, 0); - } - - closedir(d); - rmdir(dir); - - return 0; -} - -static int ask_user(int argc, char **argv) { if ((argc < 2) || strcmp(argv[1], "-y")) { @@ -89,7 +62,7 @@ jffs2_reset(int argc, char **argv) mp = find_mount_point(v->blk, 1); if (mp) { ULOG_INFO("%s is mounted as %s, only erasing files\n", v->blk, mp); - foreachdir(mp, handle_rmdir); + overlay_delete(mp, false); mount(mp, "/", NULL, MS_REMOUNT, 0); } else { ULOG_INFO("%s is not mounted, erasing it\n", v->blk); diff --git a/libfstools/libfstools.h b/libfstools/libfstools.h index a9f8576..1d41eea 100644 --- a/libfstools/libfstools.h +++ b/libfstools/libfstools.h @@ -48,4 +48,6 @@ extern int jffs2_switch(struct volume *v); extern int handle_whiteout(const char *dir); extern void foreachdir(const char *dir, int (*cb)(const char*)); +extern void overlay_delete(const char *dir, bool keep_sysupgrade); + #endif diff --git a/libfstools/overlay.c b/libfstools/overlay.c index 21012ba..c535693 100644 --- a/libfstools/overlay.c +++ b/libfstools/overlay.c @@ -32,6 +32,38 @@ #define SWITCH_JFFS2 "/tmp/.switch_jffs2" +static bool keep_sysupgrade; + +static int +handle_rmdir(const char *dir) +{ + struct dirent *dt; + struct stat st; + DIR *d; + int fd; + + d = opendir(dir); + if (!d) + return -1; + + fd = dirfd(d); + + while ((dt = readdir(d)) != NULL) { + if (fstatat(fd, dt->d_name, &st, AT_SYMLINK_NOFOLLOW) || S_ISDIR(st.st_mode)) + continue; + + if (keep_sysupgrade && !strcmp(dt->d_name, "sysupgrade.tgz")) + continue; + + unlinkat(fd, dt->d_name, 0); + } + + closedir(d); + rmdir(dir); + + return 0; +} + void foreachdir(const char *dir, int (*cb)(const char*)) { @@ -51,6 +83,13 @@ foreachdir(const char *dir, int (*cb)(const char*)) cb(dir); } +void +overlay_delete(const char *dir, bool _keep_sysupgrade) +{ + keep_sysupgrade = _keep_sysupgrade; + foreachdir(dir, handle_rmdir); +} + static int overlay_mount(struct volume *v, char *fs) {