diff --git a/include/mount.h b/include/mount.h index d0a28d81a..76a8e2442 100644 --- a/include/mount.h +++ b/include/mount.h @@ -47,6 +47,7 @@ struct mount_info { char *mountpoint; char *ns_mountpoint; unsigned flags; + unsigned sb_flags; int master_id; int shared_id; struct fstype *fstype; diff --git a/mount.c b/mount.c index a5a0d2e2b..88871282f 100644 --- a/mount.c +++ b/mount.c @@ -31,6 +31,7 @@ #include "protobuf/mnt.pb-c.h" #define AUTODETECTED_MOUNT "CRIU:AUTOGENERATED" +#define MS_PROPAGATE (MS_SHARED | MS_PRIVATE | MS_UNBINDABLE | MS_SLAVE) #undef LOG_PREFIX #define LOG_PREFIX "mnt: " @@ -1596,6 +1597,8 @@ static int dump_one_mountpoint(struct mount_info *pm, struct cr_img *img) me.root_dev = pm->s_dev; me.parent_mnt_id = pm->parent_mnt_id; me.flags = pm->flags; + me.sb_flags = pm->sb_flags; + me.has_sb_flags = true; me.mountpoint = pm->mountpoint + 1; me.source = pm->source; me.options = pm->options; @@ -1936,26 +1939,53 @@ skip_parent: return 0; } +/* + * Here are a set of flags which we know how to handle for the one mount call. + * All of them except MS_RDONLY are set only as mnt flags. + * MS_RDONLY is set for both mnt ans sb flags, so we can restore it for one + * mount call only if it set for both masks. + */ +#define MS_MNT_KNOWN_FLAGS (MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_NOATIME | \ + MS_NODIRATIME | MS_RELATIME | MS_RDONLY) static int do_new_mount(struct mount_info *mi) { - unsigned long mflags = MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE; + unsigned long sflags = mi->sb_flags; + unsigned long mflags = mi->flags & (~MS_PROPAGATE); char *src; struct fstype *tp = mi->fstype; - bool remount_ro = (tp->restore && mi->flags & MS_RDONLY); + bool remount_ro = (tp->restore && mi->sb_flags & MS_RDONLY); src = resolve_source(mi); if (!src) return -1; if (remount_ro) - mflags |= MS_RDONLY; + sflags &= ~MS_RDONLY; - if (mount(src, mi->mountpoint, tp->name, - mi->flags & ~mflags, mi->options) < 0) { + /* Merge superblock and mount flags if it's posiable */ + if (!(mflags & ~MS_MNT_KNOWN_FLAGS) && ((sflags ^ mflags) & MS_RDONLY)) { + sflags |= mflags; + mflags = 0; + } + + if (mount(src, mi->mountpoint, tp->name, sflags, mi->options) < 0) { pr_perror("Can't mount at %s", mi->mountpoint); return -1; } + if (tp->restore && tp->restore(mi)) + return -1; + + if (remount_ro) + return mount(NULL, mi->mountpoint, tp->name, + MS_REMOUNT | MS_RDONLY, NULL); + + if (mflags && mount(NULL, mi->mountpoint, NULL, + MS_REMOUNT | MS_BIND | mflags, NULL)) { + pr_perror("Unable to apply bind-mount options\n"); + return -1; + } + if (restore_shared_options(mi, !mi->shared_id && !mi->master_id, mi->shared_id, mi->master_id)) @@ -1963,12 +1993,6 @@ static int do_new_mount(struct mount_info *mi) mi->mounted = true; - if (tp->restore && tp->restore(mi)) - return -1; - - if (remount_ro) - return mount(NULL, mi->mountpoint, tp->name, - MS_REMOUNT | MS_RDONLY, NULL); return 0; } @@ -1991,6 +2015,7 @@ static int do_bind_mount(struct mount_info *mi) if (!mi->need_plugin) { char *root, *cut_root, rpath[PATH_MAX]; + unsigned long mflags; if (mi->external) { /* @@ -2044,6 +2069,13 @@ do_bind: return -1; } + mflags = mi->flags & (~MS_PROPAGATE); + if (!mi->bind || mflags != (mi->bind->flags & (~MS_PROPAGATE))) + if (mount(NULL, mi->mountpoint, NULL, MS_BIND | MS_REMOUNT | mflags, NULL)) { + pr_perror("Can't mount at %s", mi->mountpoint); + return -1; + } + if (unlikely(mi->deleted)) { if (S_ISDIR(st.st_mode)) { if (rmdir(root)) { @@ -2367,6 +2399,7 @@ static int collect_mnt_from_image(struct mount_info **pms, struct ns_id *nsid) pm->parent_mnt_id = me->parent_mnt_id; pm->s_dev = me->root_dev; pm->flags = me->flags; + pm->sb_flags = me->sb_flags; pm->shared_id = me->shared_id; pm->master_id = me->master_id; pm->need_plugin = me->with_plugin; diff --git a/proc_parse.c b/proc_parse.c index 04c7ca410..6fdd840aa 100644 --- a/proc_parse.c +++ b/proc_parse.c @@ -1089,7 +1089,7 @@ static int parse_mountinfo_ent(char *str, struct mount_info *new, char **fsname) if (!new->options) goto err; - if (parse_sb_opt(opt, &new->flags, new->options)) + if (parse_sb_opt(opt, &new->sb_flags, new->options)) goto err; ret = 0; diff --git a/protobuf/mnt.proto b/protobuf/mnt.proto index f79ae4619..12582e9d5 100644 --- a/protobuf/mnt.proto +++ b/protobuf/mnt.proto @@ -43,4 +43,5 @@ message mnt_entry { optional bool internal_sharing = 15; optional bool deleted = 16; + optional uint32 sb_flags = 17 [(criu).hex = true]; }