Skip to content

Commit bfb84a3

Browse files
committed
prepare-root: Unmount temporary var mount after /var is mounted
1 parent 1db98c0 commit bfb84a3

File tree

2 files changed

+77
-56
lines changed

2 files changed

+77
-56
lines changed

src/libostree/ostree-impl-system-generator.c

Lines changed: 73 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,35 @@ require_internal_units (const char *normal_dir, const char *early_dir, const cha
126126
#endif
127127
}
128128

129+
static gboolean
130+
write_unit_file (int dir_fd, const char *path, GCancellable *cancellable, GError **error, const char *fmt, ...)
131+
{
132+
g_auto (GLnxTmpfile) tmpf = {
133+
0,
134+
};
135+
if (!glnx_open_tmpfile_linkable_at (dir_fd, ".", O_WRONLY | O_CLOEXEC, &tmpf, error))
136+
return FALSE;
137+
g_autoptr (GOutputStream) outstream = g_unix_output_stream_new (tmpf.fd, FALSE);
138+
gsize bytes_written;
139+
va_list args;
140+
va_start (args, fmt);
141+
const gboolean r = g_output_stream_vprintf (outstream, &bytes_written, cancellable, error, fmt, args);
142+
va_end (args);
143+
if (!r)
144+
return FALSE;
145+
if (!g_output_stream_flush (outstream, cancellable, error))
146+
return FALSE;
147+
g_clear_object (&outstream);
148+
/* It should be readable */
149+
if (!glnx_fchmod (tmpf.fd, 0644, error))
150+
return FALSE;
151+
/* Error out if somehow it already exists, that'll help us debug conflicts */
152+
if (!glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_NOREPLACE, dir_fd, path,
153+
error))
154+
return FALSE;
155+
return TRUE;
156+
}
157+
129158
/* Generate var.mount */
130159
static gboolean
131160
fstab_generator (const char *ostree_target, const bool is_aboot, const char *normal_dir,
@@ -135,8 +164,37 @@ fstab_generator (const char *ostree_target, const bool is_aboot, const char *nor
135164
/* Not currently cancellable, but define a var in case we care later */
136165
GCancellable *cancellable = NULL;
137166
/* Some path constants to avoid typos */
138-
static const char fstab_path[] = "/etc/fstab";
139-
static const char var_path[] = "/var";
167+
const char *fstab_path = "/etc/fstab";
168+
const char *var_dst = "/var";
169+
const char *var_src = OTCORE_RUN_OSTREE_PRIVATE "/var";
170+
171+
/* Prepare to write to the output unit dir; we use the "normal" dir
172+
* that overrides /usr, but not /etc.
173+
*/
174+
glnx_autofd int normal_dir_dfd = -1;
175+
if (!glnx_opendirat (AT_FDCWD, normal_dir, TRUE, &normal_dir_dfd, error))
176+
return FALSE;
177+
178+
/* Generate a unit to unmount var_src */
179+
if (!write_unit_file (normal_dir_dfd, "ostree-unmount-temp-var.service", cancellable, error,
180+
"##\n# Automatically generated by ostree-system-generator\n##\n\n"
181+
"[Unit]\n"
182+
"Documentation=man:ostree(1)\n"
183+
"ConditionPathIsMountPoint=%s\n"
184+
"After=var.mount\n"
185+
"\n"
186+
"[Service]\n"
187+
"Type=oneshot\n"
188+
"ExecStart=/usr/bin/umount --lazy %s\n",
189+
var_src, var_src))
190+
return FALSE;
191+
192+
if (!glnx_shutil_mkdir_p_at (normal_dir_dfd, "local-fs.target.wants", 0755, cancellable,
193+
error))
194+
return FALSE;
195+
if (symlinkat ("../ostree-unmount-temp-var.service", normal_dir_dfd,
196+
"local-fs.target.wants/ostree-unmount-temp-var.service") < 0)
197+
return glnx_throw_errno_prefix (error, "symlinkat");
140198

141199
/* Load /etc/fstab if it exists, and look for a /var mount */
142200
g_autoptr (OtLibMountFile) fstab = setmntent (fstab_path, "re");
@@ -157,7 +215,7 @@ fstab_generator (const char *ostree_target, const bool is_aboot, const char *nor
157215
path_kill_slashes (where);
158216

159217
/* We're only looking for /var here */
160-
if (strcmp (where, var_path) != 0)
218+
if (strcmp (where, var_dst) != 0)
161219
continue;
162220

163221
found_var_mnt = TRUE;
@@ -169,59 +227,19 @@ fstab_generator (const char *ostree_target, const bool is_aboot, const char *nor
169227
if (found_var_mnt)
170228
return TRUE;
171229

172-
/* Prepare to write to the output unit dir; we use the "normal" dir
173-
* that overrides /usr, but not /etc.
174-
*/
175-
glnx_autofd int normal_dir_dfd = -1;
176-
if (!glnx_opendirat (AT_FDCWD, normal_dir, TRUE, &normal_dir_dfd, error))
177-
return FALSE;
178-
179230
/* Generate our bind mount unit */
180-
const char *var_dir = OTCORE_RUN_OSTREE_PRIVATE "/var";
181-
182-
g_auto (GLnxTmpfile) tmpf = {
183-
0,
184-
};
185-
if (!glnx_open_tmpfile_linkable_at (normal_dir_dfd, ".", O_WRONLY | O_CLOEXEC, &tmpf, error))
186-
return FALSE;
187-
g_autoptr (GOutputStream) outstream = g_unix_output_stream_new (tmpf.fd, FALSE);
188-
gsize bytes_written;
189-
/* This code is inspired by systemd's fstab-generator.c.
190-
*
191-
* Note that our unit doesn't run if systemd.volatile is enabled;
192-
* see https://github.com/ostreedev/ostree/pull/856
193-
*
194-
* To avoid having submounts of /var propagate into $stateroot/var, the mount
195-
* is made with slave+shared propagation. This means that /var will receive
196-
* mount events from the parent /sysroot mount, but not vice versa. Adding a
197-
* shared peer group below the slave group means that submounts of /var will
198-
* inherit normal shared propagation. See mount_namespaces(7), Linux
199-
* Documentation/filesystems/sharedsubtree.txt and
200-
* https://github.com/ostreedev/ostree/issues/2086. This also happens in
201-
* ostree-prepare-root.c for the INITRAMFS_MOUNT_VAR case.
202-
*/
203-
if (!g_output_stream_printf (outstream, &bytes_written, cancellable, error,
204-
"##\n# Automatically generated by ostree-system-generator\n##\n\n"
205-
"[Unit]\n"
206-
"Documentation=man:ostree(1)\n"
207-
"ConditionKernelCommandLine=!systemd.volatile\n"
208-
"Before=local-fs.target\n"
209-
"\n"
210-
"[Mount]\n"
211-
"Where=%s\n"
212-
"What=%s\n"
213-
"Options=bind,slave,shared\n",
214-
var_path, var_dir))
215-
return FALSE;
216-
if (!g_output_stream_flush (outstream, cancellable, error))
217-
return FALSE;
218-
g_clear_object (&outstream);
219-
/* It should be readable */
220-
if (!glnx_fchmod (tmpf.fd, 0644, error))
221-
return FALSE;
222-
/* Error out if somehow it already exists, that'll help us debug conflicts */
223-
if (!glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_NOREPLACE, normal_dir_dfd, "var.mount",
224-
error))
231+
if (!write_unit_file (normal_dir_dfd, "var.mount", cancellable, error,
232+
"##\n# Automatically generated by ostree-system-generator\n##\n\n"
233+
"[Unit]\n"
234+
"Documentation=man:ostree(1)\n"
235+
"ConditionKernelCommandLine=!systemd.volatile\n"
236+
"Before=local-fs.target\n"
237+
"\n"
238+
"[Mount]\n"
239+
"Where=%s\n"
240+
"What=%s\n"
241+
"Options=bind,slave,shared\n",
242+
var_dst, var_src))
225243
return FALSE;
226244

227245
/* And ensure it's required; newer systemd will auto-inject fs dependencies

src/switchroot/ostree-prepare-root.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,10 @@ main (int argc, char *argv[])
636636
if (mount_var)
637637
{
638638
if (mount (var_dir, TMP_SYSROOT "/var", NULL, MS_BIND | MS_SILENT, NULL) < 0)
639-
err (EXIT_FAILURE, "failed to bind mount /var");
639+
err (EXIT_FAILURE, "failed to bind mount %s to /var", var_dir);
640+
641+
if (umount2 (var_dir, MNT_DETACH) < 0)
642+
err (EXIT_FAILURE, "failed to umount %s", var_dir);
640643

641644
/* To avoid having submounts of /var propagate into $stateroot/var, the
642645
* mount is made with slave+shared propagation. See the comment in

0 commit comments

Comments
 (0)