Browse Source

[block] Provide abstraction to allow system to be quiesced

When performing a SAN boot via INT 13, there is no way for the
operating system to indicate that it has finished using the INT 13 SAN
device.  We therefore have no opportunity to clean up state before the
loaded operating system's native drivers take over.  This can cause
problems when booting Windows, which tends not to be forgiving of
unexpected system state.

Windows will typically write a flag to the SAN device as the last
action before transferring control to the native drivers.  We can use
this as a heuristic to bring the system to a quiescent state (without
performing a full shutdown); this provides us an opportunity to
temporarily clean up state that could otherwise prevent a successful
Windows boot.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 7 years ago
parent
commit
648657b776
3 changed files with 99 additions and 0 deletions
  1. 53
    0
      src/core/quiesce.c
  2. 15
    0
      src/core/sanboot.c
  3. 31
    0
      src/include/ipxe/quiesce.h

+ 53
- 0
src/core/quiesce.c View File

@@ -0,0 +1,53 @@
1
+/*
2
+ * Copyright (C) 2017 Michael Brown <mbrown@fensystems.co.uk>.
3
+ *
4
+ * This program is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU General Public License as
6
+ * published by the Free Software Foundation; either version 2 of the
7
+ * License, or any later version.
8
+ *
9
+ * This program is distributed in the hope that it will be useful, but
10
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU General Public License
15
+ * along with this program; if not, write to the Free Software
16
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
+ * 02110-1301, USA.
18
+ *
19
+ * You can also choose to distribute this program under the terms of
20
+ * the Unmodified Binary Distribution Licence (as given in the file
21
+ * COPYING.UBDL), provided that you have satisfied its requirements.
22
+ */
23
+
24
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
+
26
+/**
27
+ * @file
28
+ *
29
+ * Quiesce system
30
+ *
31
+ */
32
+
33
+#include <ipxe/quiesce.h>
34
+
35
+/** Quiesce system */
36
+void quiesce ( void ) {
37
+	struct quiescer *quiescer;
38
+
39
+	/* Call all quiescers */
40
+	for_each_table_entry ( quiescer, QUIESCERS ) {
41
+		quiescer->quiesce();
42
+	}
43
+}
44
+
45
+/** Unquiesce system */
46
+void unquiesce ( void ) {
47
+	struct quiescer *quiescer;
48
+
49
+	/* Call all quiescers */
50
+	for_each_table_entry ( quiescer, QUIESCERS ) {
51
+		quiescer->unquiesce();
52
+	}
53
+}

+ 15
- 0
src/core/sanboot.c View File

@@ -41,6 +41,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
41 41
 #include <ipxe/iso9660.h>
42 42
 #include <ipxe/dhcp.h>
43 43
 #include <ipxe/settings.h>
44
+#include <ipxe/quiesce.h>
44 45
 #include <ipxe/sanboot.h>
45 46
 
46 47
 /**
@@ -365,6 +366,9 @@ int sandev_reopen ( struct san_device *sandev ) {
365 366
 	struct san_path *sanpath;
366 367
 	int rc;
367 368
 
369
+	/* Unquiesce system */
370
+	unquiesce();
371
+
368 372
 	/* Close any outstanding command and restart interfaces */
369 373
 	sandev_restart ( sandev, -ECONNRESET );
370 374
 	assert ( sandev->active == NULL );
@@ -503,6 +507,9 @@ sandev_command ( struct san_device *sandev,
503 507
 	/* Sanity check */
504 508
 	assert ( ! timer_running ( &sandev->timer ) );
505 509
 
510
+	/* Unquiesce system */
511
+	unquiesce();
512
+
506 513
 	/* (Re)try command */
507 514
 	do {
508 515
 
@@ -654,6 +661,14 @@ int sandev_write ( struct san_device *sandev, uint64_t lba,
654 661
 	if ( ( rc = sandev_rw ( sandev, lba, count, buffer, block_write ) ) != 0 )
655 662
 		return rc;
656 663
 
664
+	/* Quiesce system.  This is a heuristic designed to ensure
665
+	 * that the system is quiesced before Windows starts up, since
666
+	 * a Windows SAN boot will typically write a status flag to
667
+	 * the disk as its last action before transferring control to
668
+	 * the native drivers.
669
+	 */
670
+	quiesce();
671
+
657 672
 	return 0;
658 673
 }
659 674
 

+ 31
- 0
src/include/ipxe/quiesce.h View File

@@ -0,0 +1,31 @@
1
+#ifndef _IPXE_QUIESCE_H
2
+#define _IPXE_QUIESCE_H
3
+
4
+/** @file
5
+ *
6
+ * Quiesce system
7
+ *
8
+ */
9
+
10
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
+
12
+#include <ipxe/tables.h>
13
+
14
+/** A quiescer */
15
+struct quiescer {
16
+	/** Quiesce system */
17
+	void ( * quiesce ) ( void );
18
+	/** Unquiesce system */
19
+	void ( * unquiesce ) ( void );
20
+};
21
+
22
+/** Quiescer table */
23
+#define QUIESCERS __table ( struct quiescer, "quiescers" )
24
+
25
+/** Declare a quiescer */
26
+#define __quiescer __table_entry ( QUIESCERS, 01 )
27
+
28
+extern void quiesce ( void );
29
+extern void unquiesce ( void );
30
+
31
+#endif /* _IPXE_QUIESCE_H */

Loading…
Cancel
Save