5.3 Using BFU to Install ON


The Blindingly Fast Upgrade (or Bonwick-Faulkner Upgrade) is a process used to update ON bits on a system. The ordinary Solaris upgrade procedure requires the complete WOS and takes at least 30 minutes (usually much longer). To save time, BFU uses a set of cpio(1) archives to directly overwrite the existing contents of the system. BFU often takes less than 10 minutes to run to completion, and if you are upgrading from a recent build, conflict resolution will usually take only a few minutes. Over the course of a year, using BFU can save dozens of hours of development time.

In order to use BFU, you will need to set three additional environment variables first. You can set these in your login dot-files, or on the command line. If you prefer, you could create a local wrapper for bfu(1) that sets them first. The environment variables are:

BFU is simple to use and normally takes only a single argument: a path to the set of archives you wish to install. For example, if your workspace is located in /home/jdoe/workspace, and you have completed a nightly(1) build, you would invoke bfu(1) as follows:

# bfu /home/jdoe/workspace/archives/`uname -p`/nightly

Note that, since it modifies the system software installation, bfu(1) must always be run as root.

When bfu completes there's no guarantee that the new commands and libraries are compatible with the currently running (old) kernel. Therefore, instead of exiting, bfu puts you into a subshell in which PATH=/tmp/bfubin and LD_LIBRARY_PATH=/tmp/bfulib. These directories contain the old versions of the commands and libraries commonly needed to resolve conflicts and reboot the system. They have also been modified to work with a saved copy of the old dynamic linker.

Note that you may receive warnings from BFU about being unable to copy files from "greenline.eng" or other systems or locations. In general, these warnings should be reported as bugs. However, at the time of this writing, they are harmless provided that your system is running at least Solaris 10 build 74 prior to your BFU attempt. See the latest release notes for any additional requirements and restrictions.

5.3.1 Caveats

Although it saves time, BFU is not a panacea. This section contains information about BFU's drawbacks. You should carefully evaluate these drawbacks against the benefits and decide whether BFU is appropriate to your needs. In general, unless you are an active developer, we recommend that you do not use BFU.

BFU does not update package information. Therefore you will most likely be unable to install official Solaris patches or run a full system upgrade procedure on a system which has been BFU'd. The importance of this cannot be overemphasized: IF YOU BFU YOUR SYSTEM, DO NOT ATTEMPT TO USE "NORMAL" SYSTEM MANAGEMENT PROCEDURES TO UPDATE IT IN THE FUTURE. USE BFU OR REINSTALL.

BFU does not update non-ON packages, even if newer versions of those packages are required in order to successfully install or run the version of ON you are installing. You may need to update those packages before and/or after running BFU. To understand what package updates may be needed, consult http://opensolaris.org/os/community/onnv/ for the full list of flag days between the build you are currently running and the build you wish to BFU to. Each flag day notice will instruct you as to what package updates, if any, are needed, and whether they must be completed before or after BFUing. It is critical that you read, understand, and follow these instructions exactly before running BFU. If you fail to do so you will almost certain brickify your system. See section 5.1.3 for more information about flag days.

Although the core functionality of BFU consists of the simple activity of unpacking cpio(1) archives into the running system, it also performs numerous other tasks related to the update of your system. Many of these tasks are specific to particular changes that have been made in the sources over a period of years. If your system has unusual characteristics, these additional updates can fail, which may result in a nonfunctional system. Because these updates vary greatly, it is impossible to know in advance which updates could fail, or what failure modes are possible. Although such failures are rare, they can occur. If you use BFU, you should follow the development of ON to understand changes being made that could have an adverse effect on your system. If you have doubts as to how well BFU will update a particular aspect of your system following a major change to ON, read bfu(1) and consult with the engineers who made the change.

When bfu finishes, it invokes ksh with a limited PATH. The PATH contains programs which have been specially modified to work regardless of what changes the BFU archives may contain. You can use these programs to resolve conflicts (see section 5.3.2). In particular, "reboot" works, but "init 6" does not. You can exit from this protected environment if you want, but it is not advisable unless you are sure that there have not been any "flag days" (synchronized kernel/userland changes) since your last bfu.

Never BFU in a window; always use the system console. If BFU or the system crashes in midstream, or you use the window system and it crashes or hangs, your system will be in an inconsistent state. You may be unable to boot. Therefore, you should ensure that as much of the system as possible is quiescent before starting a BFU, and be sure you have a copy of suitable system software media handy to reinstall if necessary.

Never BFU a production system. Production systems should always be updated to approved releases using the supported upgrade mechanism.

5.3.2 Resolving Conflicts

Every machine has several configuration files which get modified from the default installation; bfu keeps a list of these. This list is known as the conflicts database.

BFU saves a copy of each configuration file it would overwrite under /bfu.child; likewise, it stores a copy of each such file from the cpio archives it is extracting under /bfu.parent, having moved the previous BFU's /bfu.parent (if any) to /bfu.ancestor. We refer to the files saved under those directories as the child, parent and ancestor respectively.

When the extraction is complete, BFU diffs the various versions of these configuration files and acts according to the following rules:

* If the file is unchanged (i.e., there is no difference between the child and the parent), there is nothing to do or report.

* If the file was accepted from the parent the previous run (i.e., the child is identical to the ancestor) then the parent is accepted automatically this time; such files are marked as "update:".

* If the file is the same as the beginning of the previous file, it is assumed that the user has added lines to the end (i.e., the child consists of the parent plus some added lines); the child version is restored; such files are marked as "restore:".

* If the file differs between the parent and the child, but the parent and ancestor are identical, then it is deemed an old conflict; such files are marked as "old:".

* Lastly, if the file differs between the parent and the child, and the parent and ancestor differ as well, then it is deemed a NEW conflict; such files are marked as "NEW:".

So now we know that a NEW conflict means a file which was already different from the default, where the default has been updated. To resolve this difference, whatever changes were introduced in the new build must be ported to the existing file on the system.

Although it is possible to blindly accept the parent, this will cause any customizations in the child to be lost. As it is very common for these files to have such customizations made automatically by class action scripts from non-ON packages, this is usually a mistake, which can lead to hours of lost productivity. Therefore, there are two forms of conflict resolution which are discussed in the following two sections. They are automatic and manual conflict resolution.

If you elect to resolve conflicts manually, or if the automatic tools are unable to resolve all conflicts, you will benefit from having a proper BFU baseline installation. To establish such a baseline, you should install BFU archives corresponding to your distribution immediately after installing it. It is strongly recommended that you begin this process only if your installation is sufficiently recent that such BFU archives are available. In particular, BFUing a system older than Solaris 11 build 16 will fail and may render your system unbootable.

When BFUing to the same build as your distribution include, you can ignore all conflicts, since your existing installed configuration files are known to work correctly for this build. You must then reboot before BFUing to a later build.

5.3.2.1 Automatic Conflict Resolution

Automatic conflict resolution is performed by a script called acr. This script is available in /opt/onbld/bin and in the usr/src/tools/scripts directory of the ON workspace. In the usr/src/tools/scripts directory, the acr executable gets made from acr.sh if you do a nightly(1) build with the -t option. There is man page, acr.1, in /opt/onbld/man/man1 and in the usr/src/tools/scripts directory of the ON workspace.

The standard way to use acr is to invoke it while still in the protected environment after a BFU is performed. In this mode there is no need to specify any command line parameters.

For more specialized applications, acr accepts one or two parameters. The first parameter is the name of an alternate root directory. The second parameter, if specified, is the name of the directory containing the archives.

acr uses a file called conflict_resolution.gz in the directory containing the BFU cpio archives. This conflict resolution file is constructed whenever nightly(1) creates archives. That is to say whenever nightly(1) is run with the -a option.

When acr runs, it lists the files that it is processing to standard out. Detailed results are written to a file called allresults in a subdirectory of /tmp. When acr exits, it prints the full path name of the allresults file. The allresults should be examined to ensure that no errors occurred during acr processing. If errors occurred, you will need to resort to manual conflict resolution discussed in the next section.

5.3.2.2 Manual Conflict Resolution

Manual conflict resolution requires you to resolve each of the conflicts by hand. The general way to resolve conflicts is:

% diff /bfu.ancestor/$file /bfu.parent/$file

then manually apply the diffs to /$file. Note that you will not have /bfu.ancestor if you have not previously BFU'd; therefore you will find manual conflict resolution easier if you have established a baseline as described above. For many files, a short-cut can be employed. BFU drops you in /bfu.conflicts when it completes, and most changes are additions or modifications, so doing:

% diff $file /$file

and making sure the diffs all point to the right (i.e., ">" rather than "<") will do the trick. This will not work in all cases, however; some notable exceptions are detailed below.

etc/name_to_major

This file matches device names with major numbers; it is critical that each device have a unique major number. Diffing the ancestor with the parent is a good start -- just remember that the name is important, but the major number may vary. Old devices which have been removed in the parent should be deleted, but if you're not sure, just leave them alone as they are generally harmless. New devices should be added with an unused major number (if it's available, use the one from the diffs). Never change the number for an existing entry unless you are sure you know what you are doing. If you are in doubt as to what changed, you can consult the history of the files directly from your workspace (e.g. usr/src/uts/{intel|sparc}/os/name_to_major).

Once finished, you can sanity-check your changes by running:

% sort -k1,1 /etc/name_to_major | sort -uc -k1,1
% sort -k2n /etc/name_to_major | sort -uc -k2n

These report the first duplicated device name and the lowest duplicated major number, respectively. Either of these indicates a problem that you must correct before rebooting. If there is no output, you're all set. Note that the kernel will also warn you of such conflicts after you reboot, but by then it may be too late.

etc/security/*_attr

These files tend to get shuffled around quite a bit by class-action scripts, so the parent and child versions can differ wildly. For these, the shortcut described above is ineffective, but the more general diff of the ancestor with the parent works well.

In general, only NEW conflicts need to be examined.

5.3.3 BFU and Zones

The contents of each zone are copied from the global zone when the zone is created. To ensure that all zones remain operational after BFUing, it is necessary to keep the zone contents consistent with those in the global zone. To do this, BFU will update each zone in turn once the global zone has been updated; however, because each zone may have configuration files that differ from the global zone's, each zone has its own BFU conflict management directories. Unfortunately, it is not possible to BFU only a single zone. BFU affects the entire system including all zones. If you want to test userspace changes in a zone, you will need to copy files from your proto area into that zone manually.

It is safest to shut down all zones before BFUing your system. This will ensure that dependencies which may be violated by the files being installed will not break a zone.

After BFUing a system with zones other than the global zone, you will need to first resolve conflicts in the global zone, then resolve conflicts in each remaining zone before rebooting the system. Resolving BFU conflicts in a zone works exactly the same way as for the global zone; however, in many cases it will not be necessary to manually merge the file contents. Instead you are likely to find that the file should be identical to that in the global zone, and you can simply copy it over. After resolving conflicts in all zones, you must reboot your system before rebooting any zone.