Oracle EBS R12.2 Dual File System Demystified: Run Edition, Patch Edition, and ADOP Explained

Many Oracle EBS DBAs know how to run ADOP. Fewer understand why the dual file system exists or what is actually happening behind each phase. This post fills that gap — the architecture first, then the lifecycle, then the real-world traps.

Why two file systems exist

The biggest shift moving from R12.1 to R12.2 is that the application tier is no longer one file system. R12.2 keeps two full, identical copies of the application code — fs1 and fs2 — plus a third, non-editioned area, fs_ne.

At any moment one of fs1/fs2 is the run file system (what users are connected to) and the other is the patch file system (where ADOP applies patches in the background). That is the whole point: you patch the idle copy while users keep working on the live one, then switch over in a short cutover window.

The layout on disk

/u01/oracle/<SID>/
│
├── fs1      (RUN or PATCH)
├── fs2      (PATCH or RUN)
└── fs_ne    (Non-editioned — never swaps)

The two never have fixed roles. After every cycle the labels swap, so fs1 might be run today and patch after the next cutover:

Before Cutover                 After Cutover

   Users                          Users
     |                              |
     v                              v
   RUN  = fs1                     RUN  = fs2
   PATCH = fs2                    PATCH = fs1

If you remember only one thing from this article, remember this: fs1 and fs2 are just labels. RUN and PATCH are the roles that matter.

Never hardcode a path assuming fs1 is always live. Read the environment, don’t memorize it.

Determining the current run and patch file systems

This is one of the most common questions in R12.2, and the answer is in the environment, not in your head:

source EBSapps.env run

echo "RUN_BASE     = $RUN_BASE"
echo "PATCH_BASE   = $PATCH_BASE"
echo "FILE_EDITION = $FILE_EDITION"

Example output:

RUN_BASE     = /u01/oracle/<SID>/fs1
PATCH_BASE   = /u01/oracle/<SID>/fs2
FILE_EDITION = run

FILE_EDITION tells you which copy your current shell is pointed at. A surprising number of “my patch went to the wrong place” problems are just someone working in the wrong edition’s shell.

What fs_ne is and why it exists

Most write-ups mention fs_ne and move on. It matters because it holds everything that must survive a cutover unchanged:

fs_ne (non-editioned) contains data that must NOT switch at cutover:

  - Concurrent Manager logs and output
  - Application / debug logs
  - Inbound interface files
  - Outbound interface files
  - Custom file drops
  - Temp files

If these lived inside fs1 and fs2, they would belong to whichever copy was live — and the moment you cut over to the other copy, those files would appear to “vanish.” Pulling them into a single non-editioned area means logs and interface files stay put no matter which file system is running.

File system editions and database editions

R12.2 pairs the dual file system with Edition-Based Redefinition (EBR) on the database. Each patching cycle stacks a new database edition on top of the last:

COL edition_name        FORMAT A28
COL parent_edition_name FORMAT A28
COL usable              FORMAT A8

SELECT edition_name,
       NVL(parent_edition_name,'-') AS parent_edition_name,
       usable
FROM   dba_editions
ORDER  BY edition_name;
EDITION_NAME                 PARENT_EDITION_NAME          USABLE
---------------------------- ---------------------------- --------
ORA$BASE                     -                            YES
V_20260115_0830              ORA$BASE                     YES
V_20260301_2145              V_20260115_0830              YES

The run edition is the currently active database edition. During prepare, ADOP creates a new child patch edition where database changes are applied. During cutover, that patch edition becomes the new run edition. The file system and the database edition move together — patch edition on the patch file system, run edition on the run file system.

The ADOP cycle, phase by phase

ADOP (AD Online Patching) drives everything. A full cycle is five phases:

  1. prepare — validates the environment, synchronizes the patch file system with the run file system when necessary, and creates the new database patch edition. Run and patch are now identical and ready to diverge.
  2. apply — applies your patch(es) to the patch file system and patch edition only. Users are untouched. You can apply many patches across multiple apply calls in one cycle.
  3. finalize — does the heavy compile/precompute work it can do before cutover, to keep the downtime window short.
  4. cutover — the only disruptive step. Services bounce, the patch file system becomes the new run, and the patch edition becomes the new run edition.
  5. cleanup — drops obsolete editions and old objects so the system is ready for the next cycle.

“Online patching” — so why do users still get disconnected?

This is the question every customer asks. The honest answer: only cutover is disruptive.

Prepare    ->  No downtime
Apply      ->  No downtime
Finalize   ->  No downtime
Cutover    ->  DOWNTIME  (services stop and restart on the patched FS)
Cleanup    ->  No downtime

All the slow work — applying patches, compiling, copying files — happens on the idle patch file system while users keep working. The only outage is the cutover window.

What actually happens during cutover

During cutover:

1. Application services stop.
2. Database patch edition becomes the new run edition.
3. Patch file system becomes the new run file system.
4. Context files are updated.
5. Application services restart.
6. Users reconnect to the newly patched environment.

That sequence is the bridge between the architecture and what you actually watch happen in the logs during your maintenance window.

Monitoring an ADOP session

Check where any cycle stands with the status command and the AD tables:

adop -status
COL node_name   FORMAT A14
COL prepare     FORMAT A8
COL apply       FORMAT A8
COL cutover     FORMAT A8
COL cleanup     FORMAT A8
COL status      FORMAT A12

SELECT adop_session_id,
       node_name,
       NVL(prepare_status,'-')  AS prepare,
       NVL(apply_status,'-')    AS apply,
       NVL(cutover_status,'-')  AS cutover,
       NVL(cleanup_status,'-')  AS cleanup,
       NVL(status,'-')          AS status
FROM   ad_adop_sessions
ORDER  BY adop_session_id DESC;

A clean idle system shows the last session fully completed. A row stuck mid-phase is an abandoned cycle that must be sorted before the next patch — you cannot start a fresh prepare cleanly on top of a half-finished one.

fs_clone: the part that bites people

fs_clone resyncs the patch file system from run so the two start identical:

adop phase=fs_clone

You run it explicitly when the file systems have drifted — after a failed cutover, a manual change to one side, or a long gap since the last cycle. prepare also triggers it internally when it detects drift.

It rarely fails because of the clone logic. It fails on file ownership and permissions. fs_clone deletes and rebuilds the patch file system’s middleware home (FMW_Home), and if something there is not owned by the apps OS user, the delete stalls. The classic case is OHS files that ended up root-owned after a privileged process touched them. The clone tries to remove FMW_Home, hits files it cannot delete, and aborts.

Safe recovery is to move the blocking tree aside rather than force-delete it:

# As the apps owner, after confirming what is in there:
mv $PATCH_BASE/FMW_Home $PATCH_BASE/FMW_Home_stale_$(date +%Y%m%d)
# then re-run
adop phase=fs_clone

mv over rm -rf is deliberate. A recursive force-delete on a partially root-owned tree on a production node is how a recoverable patch problem becomes a restore-from-backup problem. Rename it aside, let fs_clone rebuild cleanly, and clear the stale copy later once the system is confirmed healthy. If root-owned files genuinely must be removed, get the ownership corrected through the proper channel — not a blind sudo rm on a live box.

Plan for space

Remember that R12.2 maintains two complete application file systems plus fs_ne. Any major patching activity, an fs_clone, or a technology stack upgrade can temporarily require significantly more space than a comparable R12.1 environment. fs_clone failing with cryptic errors is often nothing more than a full mount — check headroom before you start, not after it fails halfway. This is a lesson many administrators learn the hard way.

ADOP command quick reference

adop -status                          # where does the current/last cycle stand

adop phase=prepare                    # sync patch FS, create patch edition
adop phase=apply patches=12345678     # apply patch to patch FS / patch edition
adop phase=finalize                   # pre-cutover compile work
adop phase=cutover                    # the downtime step — switch run/patch
adop phase=cleanup                    # drop obsolete editions and objects

adop phase=fs_clone                   # resync patch FS from run after drift
adop phase=abort                      # cleanly abandon an in-progress cycle

Common real-world mistakes

1. Assuming fs1 is always RUN.
2. Applying custom changes directly on the RUN file system.
3. Forgetting fs_clone after manual changes to one file system.
4. Running out of disk space during fs_clone or apply.
5. Leaving an ADOP session unfinished (blocks the next prepare).
6. Ignoring cleanup for months (editions pile up, performance degrades).
7. Modifying or letting processes touch FMW_Home as root.
8. Making custom changes on the RUN file system and forgetting to sync them
   to PATCH before the next ADOP cycle (lost custom JSPs, forms, and reports
   after cutover; unexplained differences between fs1 and fs2).

Most production ADOP pain traces back to one of these eight, not to the tool itself.

In summary

Oracle EBS R12.2 achieves near-zero downtime patching by combining two application file systems (fs1/fs2) with Edition-Based Redefinition in the database. While users continue working on the run edition, patches are applied to an isolated patch edition. During cutover, Oracle switches application services from the old run file system and database edition to the newly patched run file system and edition.

A few principles to carry away:

  • Run/patch roles are not fixed — read the environment, never assume fs1 is live.
  • fs_ne is non-editioned so logs and interface files survive cutover instead of vanishing.
  • Only cutover causes an outage. Everything else runs during business hours.
  • Most fs_clone failures are ownership problems on FMW_Home. Move the blocking tree aside and let it rebuild; reach for rm -rf only as an absolute last resort and never against a partially root-owned tree.
  • Treat disk space, edition awareness, and cleanup as routine discipline. The architecture is forgiving when you respect those and unforgiving when you don’t.

Understanding ADOP becomes much easier when you stop thinking about patches and start thinking about roles: one file system serves users, the other is prepared for the next cutover.


Disclaimer: All paths, identifiers, and examples in this post are anonymized and generic. They do not represent any specific client, employer, or environment. Views are my own.


Discover more from Syed Anwar Ahmed – Oracle DBA Blog

Subscribe to get the latest posts sent to your email.

Comments

Leave a comment

Discover more from Syed Anwar Ahmed – Oracle DBA Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading