doc: relocate notes from arch to txt
[openafs.git] / doc / arch / dafs-overview.txt
diff --git a/doc/arch/dafs-overview.txt b/doc/arch/dafs-overview.txt
deleted file mode 100644 (file)
index 2b2e586..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-The Demand-Attach FileServer (DAFS) has resulted in many changes to how
-many things on AFS fileservers behave. The most sweeping changes are
-probably in the volume package, but significant changes have also been
-made in the SYNC protocol, the vnode package, salvaging, and a few
-miscellaneous bits in the various fileserver processes.
-
-This document serves as an overview for developers on how to deal with
-these changes, and how to use the new mechanisms. For more specific
-details, consult the relevant doxygen documentation, the code comments,
-and/or the code itself.
-
- - The salvageserver
-
-The salvageserver (or 'salvaged') is a new OpenAFS fileserver process in
-DAFS. This daemon accepts salvage requests via SALVSYNC (see below), and
-salvages a volume group by fork()ing a child, and running the normal
-salvager code (it enters vol-salvage.c by calling SalvageFileSys1).
-
-Salvages that are initiated from a request to the salvageserver (called
-'demand-salvages') occur automatically; whenever the fileserver (or
-other tool) discovers that a volume needs salvaging, it will schedule a
-salvage on the salvageserver without any intervention needed.
-
-When scheduling a salvage, the vol id should be the id for the volume
-group (the RW vol id). If the salvaging child discovers that it was
-given a non-RW vol id, it will send the salvageserver a SALVSYNC LINK
-command, and will exit. This will tell the salvageserver that whenever
-it receives a salvage request for that vol id, it should schedule a
-salvage for the corresponding RW id instead.
-
- - FSSYNC/SALVSYNC
-
-The FSSYNC and SALVSYNC protocols are the protocols used for
-interprocess communication between the various fileserver processes.
-FSSYNC is used for querying the fileserver for volume metadata,
-'checking out' volumes from the fileserver, and a few other things.
-SALVSYNC is used to schedule and query salvages in the salvageserver.
-
-FSSYNC existed prior to DAFS, but it encompasses a much larger set of
-commands with the advent of DAFS. SALVSYNC is entirely new to DAFS.
-
- -- SYNC
-
-FSSYNC and SALVSYNC are both layered on top of a protocol called SYNC.
-SYNC isn't much a protocol in itself; it just handles some boilerplate
-for the messages passed back and forth, and some error codes common to
-both FSSYNC and SALVSYNC.
-
-SYNC is layered on top of TCP/IP, though we only use it to communicate
-with the local host (usually via a unix domain socket). It does not
-handle anything like authentication, authorization, or even things like
-serialization. Although it uses network primitives for communication,
-it's only useful for communication between processes on the same
-machine, and that is all we use it for.
-
-SYNC calls are basically RPCs, but very simple. The calls are always
-synchronous, and each SYNC server can only handle one request at a time.
-Thus, it is important for SYNC server handlers to return as quickly as
-possible; hitting the network or disk to service a SYNC request should
-be avoided to the extent that such is possible.
-
-SYNC-related source files are src/vol/daemon_com.c and
-src/vol/daemon_com.h
-
- -- FSSYNC
-
- --- server
-
-The FSSYNC server runs in the fileserver; source is in
-src/vol/fssync-server.c.
-
-As mentioned above, FSSYNC handlers should finish quickly when
-servicing a request, so hitting the network or disk should be avoided.
-In particular, you absolutely cannot make a SALVSYNC call inside an
-FSSYNC handler; the SALVSYNC client wrapper routines actively prevent
-this from happening, so even if you try to do such a thing, you will not
-be allowed to. This prohibition is to prevent deadlock, since the
-salvageserver could have made the FSSYNC request that you are servicing.
-
-When a client makes a FSYNC_VOL_OFF or NEEDVOLUME request, the
-fileserver offlines the volume if necessary, and keeps track that the
-volume has been 'checked out'. A volume is left online if the checkout
-mode indicates the volume cannot change (see VVolOpLeaveOnline_r).
-
-Until the volume has been 'checked in' with the ON, LEAVE_OFFLINE, or
-DONE commands, no other program can check out the volume.
-
-Other FSSYNC commands include abilities to query volume metadata and
-stats, to force volumes to be attached or offline, and to update the
-volume group cache. See doc/arch/fssync.txt for documentation on the
-individual FSSYNC commands.
-
- --- clients
-
-FSSYNC clients are generally any OpenAFS process that runs on a
-fileserver and tries to access volumes directly. The volserver,
-salvageserver, and bosserver all qualify, as do (sometimes) some
-utilities like vol-info or vol-bless. For issuing FSSYNC commands
-directly, there is the debugging tool fssync-debug.  FSSYNC client code
-is in src/vol/fssync-client.c, but it's not very interesting.
-
-Any program that wishes to directly access a volume on disk must check
-out the volume via FSSYNC (NEEDVOLUME or OFF commands), to ensure the
-volume doesn't change while the program is using it. If the program
-determines that the volume is somehow inconsistent and should be
-salvaged, it should send the FSSYNC command FORCE_ERROR with reason code
-FSYNC_SALVAGE to the fileserver, which will take care of salvaging it.
-
- -- SALVSYNC
-
-The SALVSYNC server runs in the salvageserver; code is in
-src/vol/salvsync-server.c. SALVSYNC clients are just the fileserver, the
-salvageserver run with the -client switch, and the salvageserver worker
-children. If any other process notices that a volume needs salvaging, it
-should issue a FORCE_ERROR FSSYNC command to the fileserver with the
-FSYNC_SALVAGE reason code.
-
-The SALVSYNC protocol is simpler than the FSSYNC protocol. The commands
-are basically just to create, cancel, change, and query salvages. The
-RAISEPRIO command increases the priority of a salvage job that hasn't
-started yet, so volumes that are accessed more frequently will get
-salvaged first. The LINK command is used by the salvageserver worker
-children to inform the salvageserver parent that it tried to salvage a
-readonly volume for which a read-write clone exists (in which case we
-should just schedule a salvage for the parent read-write volume).
-
-Note that canceling a salvage is just for salvages that haven't run
-yet; it only takes a salvage job off of a queue; it doesn't stop a
-salvageserver worker child in the middle of a salvage.
-
- - The volume package
-
- -- refcounts
-
-Before DAFS, the Volume struct just had one reference count, vp->nUsers.
-With DAFS, we know have the notion of an internal/lightweight reference
-count, and an external/heavyweight reference count. Lightweight refs are
-acquired with VCreateReservation_r, and released with
-VCancelReservation_r. Heavyweight refs are acquired as before, normally
-with a GetVolume or AttachVolume variant, and releasing the ref with
-VPutVolume.
-
-Lightweight references are only acquired within the volume package; a vp
-should not be given to e.g. the fileserver code with an extra
-lightweight ref. A heavyweight ref is generally acquired for a vp that
-will be given to some non-volume-package code; acquiring a heavyweight
-ref guarantees that the volume header has been loaded.
-
-Acquiring a lightweight ref just guarantees that the volume will not go
-away or suddenly become unavailable after dropping VOL_LOCK. Certain
-operations like detachment or scheduling a salvage only occur when all
-of the heavy and lightweight refs go away; see VCancelReservation_r.
-
- -- state machine
-
-Instead of having a per-volume lock, each vp always has an associated
-'state', that says what, if anything, is occurring to a volume at any
-particular time; or if the volume is attached, offline, etc. To do the
-basic equivalent of a lock -- that is, ensure that nobody else will
-change the volume when we drop VOL_LOCK -- you can put the volume in
-what is called an 'exclusive' state (see VIsExclusiveState).
-
-When a volume is in an exclusive state, no thread should modify the
-volume (or expect the vp data to stay the same), except the thread that
-put it in that state. Whenever you manipulate a volume, you should make
-sure it is not in an exclusive state; first call VCreateReservation_r to
-make sure the volume doesn't go away, and then call
-VWaitExclusiveState_r. When that returns, you are guaranteed to have a
-vp that is in a non-exclusive state, and so can me manipulated. Call
-VCancelReservation_r when done with it, to indicate you don't need it
-anymore.
-
-Look at the definition of the VolState enumeration to see all volume
-states, and a brief explanation of them.
-
- -- VLRU
-
-See: Most functions with VLRU in their name in src/vol/volume.c.
-
-The VLRU is what dictates when volumes are detached after a certain
-amount of inactivity. The design is pretty much a generational garbage
-collection mechanism. There are 5 queues that a volume can be on the
-VLRU (VLRUQueueName in volume.h). 'Candidate' volumes haven't seen
-activity in a while, and so are candidates to be detached. 'New' volumes
-have seen activity only recently; 'mid' volumes have seen activity for
-awhile, and 'old' volumes have seen activity for a long while. 'Held'
-volumes cannot be soft detached at all.
-
-Volumes are moved from new->mid->old if they have had activity recently,
-and are moved from old->mid->new->candidate if they have not had any
-activity recently. The definition of 'recently' is configurable by the
--vlruthresh fileserver parameter; see VLRU_ComputeConstants for how they
-are determined. Volumes start at 'new' on attachment, and if any
-activity occurs when a volume is on 'candidate', it's moved to 'new'
-immediately.
-
-Volumes are generally promoted/demoted and soft-detached by
-VLRU_ScannerThread, which runs every so often and moves volumes between
-VLRU queues depending on their last access time and the various
-thresholds (or soft-detaches them, in the case of the 'candidate'
-queue). Soft-detaching just means the volume is taken offline and put
-into the preattached state.
-
- --- DONT_SALVAGE
-
-The dontSalvage flag in volume headers can be set to DONT_SALVAGE to
-indicate that a volume probably doesn't need to be salvaged. Before
-DAFS, volumes were placed on an 'UpdateList' which was periodically
-scanned, and dontSalvage was set on volumes that hadn't been touched in
-a while.
-
-With DAFS and the VLRU additions, setting dontSalvage now happens when a
-volume is demoted a VLRU generation, and no separate list is kept. So if
-a volume has been idle enough to demote, and it hasn't been accessed in
-SALVAGE_INTERVAL time, dontSalvage will be set automatically by the VLRU
-scanner.
-
- -- Vnode
-
-Source files: src/vol/vnode.c, src/vol/vnode.h, src/vol/vnode_inline.h
-
-The changes to the vnode package are largely very similar to those in
-the volume package. A Vnode is put into specific states, some of which
-are exclusive and act like locks (see VnChangeState_r,
-VnIsExclusiveState). Vnodes also have refcounts, incremented and
-decremented with VnCreateReservation_r and VnCancelReservation_r like
-you would expect. I/O should be done outside of any global locks; just
-the vnode is 'locked' by being put in an exclusive state if necessary.
-
-In addition to a state, vnodes also have a count of readers. When a
-caller gets a vnode with a read lock, we of course must wait for the
-vnode to be in a nonexclusive state (VnWaitExclusive_r), then the number
-of readers is incremented (VnBeginRead_r), but the vnode is kept in a
-non-exclusive state (VN_STATE_READ).
-
-When a caller gets a vnode with a write lock, we must wait not only for
-the vnode to be in a nonexclusive state, but also for there to be no
-readers (VnWaitQuiescent_r), so we can actually change it.
-
-VnLock still exists in DAFS, but it's almost a no-op. All we do for DAFS
-in VnLock is set vnp->writer to the current thread id for a write lock,
-for some consistency checks later (read locks are actually no-ops).
-Actual mutual exclusion in DAFS is done by the vnode state machine and
-the reader count.
-
- - viced state serialization
-
-See src/viced/serialize_state.* and ShutDownAndCore in
-src/viced/viced.c
-
-Before DAFS, whenever a fileserver restarted, it lost all information
-about all clients, what callbacks they had, etc. So when a client with
-existing callbacks contacted the fileserver, all callback information
-needed to be reset, potentially causing a bunch of unnecessary traffic.
-And of course, if the client does not contact the fileserver again, it
-could not get sent callbacks it should get sent.
-
-DAFS now has the ability to save the host and CB data to a file on
-shutdown, and restore it when it starts up again. So when a fileserver
-is restarted, the host and CB information should be effectively the same
-as when it shut down. So a client may not even know if a fileserver was
-restarted.
-
-Getting this state information can be a little difficult, since the host
-package data structures aren't necessarily always consistent, even after
-H_LOCK is dropped. What we attempt to do is stop all of the background
-threads early in the shutdown process (set fs_state.mode -
-FS_MODE_SHUTDOWN), and wait for the background threads to exit (or be
-marked as 'tranquil'; see the fs_state struct) later on, before trying
-to save state. This makes it a lot less likely for anything to be
-modifying the host or CB structures by the time we try to save them.
-
- - volume group cache
-
-See: src/vol/vg_cache* and src/vol/vg_scan.c
-
-The VGC is a mechanism in DAFS to speed up volume salvages. Pre-VGC,
-whenever the salvager code salvaged an individual volume, it would need
-to read all of the volume headers on the partition, so it knows what
-volumes are in the volume group it is salvaging, so it knows what
-volumes to tell the fileserver to take offline. With demand-salvages,
-this can make salvaging take a very long time, since the time to read in
-all volume headers can take much more time than the time to actually
-salvage a single volume group.
-
-To prevent the need to scan the partition volume headers every single
-time, the fileserver maintains a cache of which volumes are in what
-volume groups. The cache is populated by scanning a partition's volume
-headers, and is started in the background upon receiving the first
-salvage request for a partition (VVGCache_scanStart_r,
-_VVGC_scan_start).
-
-After the VGC is populated, it is kept up to date with volumes being
-created and deleted via the FSSYNC VG_ADD and VG_DEL
-commands. These are called every time a volume header is created,
-removed, or changed when using the volume header wrappers in vutil.c
-(VCreateVolumeDiskHeader, VDestroyVolumeDiskHeader,
-VWriteVolumeDiskHeader). These wrappers should always be used to
-create/remove/modify vol headers, to ensure that the necessary FSSYNC
-commands are called.
-
- -- race prevention
-
-In order to prevent races between volume changes and VGC partition scans
-(that is, someone scans a header while it is being written and not yet
-valid), updates to the VGC involving adding or modifying volume headers
-should always be done under the 'partition header lock'. This is a
-per-partition lock to conceptually lock the set of volume headers on
-that partition. It is only read-held when something is writing to a
-volume header, and it is write-held for something that is scanning the
-partition for volume headers (the VGC or partition salvager). This is a
-little counterintuitive, but it is what we want.  We want multiple
-headers to be written to at once, but if we are the VGC scanner, we want
-to ensure nobody else is writing when we look at a header file.
-
-Because the race described above is so rare, vol header scanners don't
-actually hold the lock unless a problem is detected. So, what they do is
-read a particular volume header without any lock, and if there is a
-problem with it, they grab a write lock on the partition vol headers,
-and try again. If it still has a problem, the header is just faulty; if
-it's okay, then we avoided the race.
-
-Note that destroying vol headers does not require any locks, since
-unlink()s are atomic and don't cause any races for us here.
-
- - partition and volume locking
-
-Previously, whenever the volserver would attach a volume or the salvager
-would salvage anything, the partition would be locked
-(VLockPartition_r). This unnecessarily serializes part of most volserver
-operations. It also makes it so only one salvage can run on a partition
-at a time, and that a volserver operation cannot occur at the same time
-as a salvage. With the addition of the VGC (previous section), the
-salvager partition lock is unnecessary on namei, since the salvager does
-not need to scan all volume headers.
-
-Instead of the rather heavyweight partition lock, in DAFS we now lock
-individual volumes. Locking an individual volume is done by locking a
-certain byte in the file /vicepX/.volume.lock. To lock volume with ID
-1234, you lock 1 byte at offset 1234 (with VLockFile: fcntl on unix,
-LockFileEx on windows as of the time of this writing). To read-lock the
-volume, acquire a read lock; to write-lock the volume, acquire a write
-lock.
-
-Due to the potentially very large number of volumes attached by the
-fileserver at once, the fileserver does not keep volumes locked the
-entire time they are attached (which would make volume locking
-potentially very slow). Rather, it locks the volume before attaching,
-and unlocks it when the volume has been attached. However, all other
-programs are expected to acquire a volume lock for the entire duration
-they interact with the volume. Whether a read or write lock is obtained
-is determined by the attachment mode, and whether or not the volume in
-question is an RW volume (see VVolLockType()).
-
-These locks are all acquired non-blocking, so we can just fail if we
-fail to acquire a lock. That is, an errant process holding a file-level
-lock cannot cause any process to just hang, waiting for a lock.
-
- -- re-reading volume headers
-
-Since we cannot know whether a volume is writable or not until the
-volume header is read, and we cannot atomically upgrade file-level
-locks, part of attachment can now occur twice (see attach2 and
-attach_volume_header). What occurs is we read the vol header, assuming
-the volume is readonly (acquiring a read or write lock as necessary).
-If, after reading the vol header, we discover that the volume is
-writable and that means we need to acquire a write lock, we read the vol
-header again while acquiring a write lock on the header.
-
- -- verifying checkouts
-
-Since the fileserver does not hold volume locks for the entire time a
-volume is attached, there could have been a potential race between the
-fileserver and other programs. Consider when a non-fileserver program
-checks out a volume from the fileserver via FSSYNC, then locks the
-volume. Before the program locked the volume, the fileserver could have
-restarted and attached the volume. Since the fileserver releases the
-volume lock after attachment, the fileserver and the other program could
-both think they have control over the volume, which is a problem.
-
-To prevent this non-fileserver programs are expected to verify that
-their volume is checked out after locking it (FSYNC_VerifyCheckout).
-What this does is ask the fileserver for the current volume operation on
-the specific volume, and verifies that it matches how the program
-checked out the volume.
-
-For example, programType X checks out volume V from the fileserver, and
-then locks it. We then ask the fileserver for the current volume
-operation on volume V. If the programType on the vol operation does not
-match (or the PID, or the checkout mode, or other things), we know the
-fileserver must have restarted or something similar, and we do not have
-the volume checked out like we thought we did.
-
-If the program determines that the fileserver may have restarted, it
-then must retry checking out and locking the volume (or return an
-error).