FSTRANS(9) | Kernel Developer's Manual | FSTRANS(9)

# NAME

`fstrans`, `fstrans_setstate`, `fstrans_getstate`, `fstrans_start`, `fstrans_start_nowait`, `fstrans_start_lazy`, `fstrans_done`, `fstrans_is_owner`, `fscow_establish`, `fscow_disestablish`, `fscow_run` —
file system suspension helper subsystem

# SYNOPSIS

`#include <sys/mount.h>`
`#include <sys/fstrans.h>`

void
`fstrans_start`(struct mount *mp);

int
`fstrans_start_nowait`(struct mount *mp);

void
`fstrans_start_lazy`(struct mount *mp);

void
`fstrans_done`(struct mount *mp);

int
`fstrans_setstate`(struct mount *mp, enum fstrans_state new_state);

enum fstrans_state
`fstrans_getstate`(struct mount *mp);

int
`fstrans_is_owner`(struct mount *mp);

int
`fscow_establish`(struct mount *mp, int (*func)(void *, struct buf *, bool), void *cookie);

int
`fscow_disestablish`(struct mount *mp, int (*func)(void *, struct buf *, bool), void *cookie);

int
`fscow_run`(struct buf *bp, bool data_valid);

# DESCRIPTION

The `fstrans` subsystem assists file system suspension and copy-on-write snapshots.

The file system's normal operations, such as its vnodeops(9), must be bracketed by `fstrans_start`() and `fstrans_done`() in a shared transaction, which is blocked by suspending the file system and while it is suspended.

Operations needed while suspending the file system must be bracketed by `fstrans_start_lazy`() and `fstrans_done`() in a lazy transaction, which is allowed while suspending the file system, but blocked while the file system is suspended.

Transactions are per-thread and nestable: if a thread is already in a transaction, it can enter another transaction without blocking. Each `fstrans_start`() must be paired with `fstrans_done`(). Transactions for multiple distinct mount points may not be nested.

The file system's VFS_SUSPENDCTL(9) method can use `fstrans_setstate`() to:

- enter the `FSTRANS_SUSPENDING` state to suspend all normal operations but allow lazy transactions,
- enter the `FSTRANS_SUSPENDED` state to suspend all operations, and
- restore to the `FSTRANS_NORMAL` state to resume all operations.

A file system supporting `fstrans` may establish a copy-on-write callback with `fscow_establish`(). The copy-on-write callback will be called every time a buffer is written to a block device with `VOP_STRATEGY`() and every time a buffer is read into the buffercache(9) with `B_MODIFY` set indicating the caller's intent to modify it. Anyone modifying a buffer may additionally use `fscow_run`() to explicitly invoke the established callback. The copy-on-write callback must be disestablished with `fscow_disestablish`() when the file system is done with it.

# FUNCTIONS

`fstrans_start`(mp)
  Enter a transaction on the file system mp in the current thread. If the file system is in a state that blocks such transactions, wait until it changes state to one that does not.

  If the file system is suspended, wait until it is resumed.

  However, if the current thread is already in a transaction on mp, `fstrans_start`() will enter a nested transaction and return immediately without waiting.

  May sleep.

`fstrans_start_nowait`(mp)
  Like `fstrans_start`(), but return `EBUSY` immediately if transactions are blocked in its current state.

  May sleep nevertheless on internal locks.

`fstrans_start_lazy`(mp)
  Like `fstrans_start`(), but will not block while suspending.

  May sleep.

`fstrans_done`(mp)
  End the current transaction on mp.
`fstrans_getstate`(mp)
  Return the current state of the file system mp.

  Must be called within a transaction for the answer to be stable.

`fstrans_setstate`(mp, new_state)
  Change the state of the file system mp to new_state, and wait for all transactions not allowed in new_state to complete.
  `FSTRANS_NORMAL`
    Allow all transactions.
  `FSTRANS_SUSPENDING`
    Block `FSTRANS_SHARED` transactions but allow `FSTRANS_LAZY` transactions.
  `FSTRANS_SUSPENDED`
    Block all transactions.

  A thread that changes a file system to a state other than `FSTRANS_NORMAL` enters a transaction for the purposes of `fstrans_getstate`() until it changes state back to `FSTRANS_NORMAL`.

  Additionally, a thread that changes a file system to a state other than `FSTRANS_NORMAL` acquires an exclusive lock on the file system state, so that `fstrans_is_owner`() will return true in that thread, and no other thread can change the file system's state until the owner restores it to `FSTRANS_NORMAL`.

  May sleep, and may be interrupted by a signal. On success, return zero. On failure, restore the file system to the `FSTRANS_NORMAL` state and return an error code. `fstrans_setstate`() never fails if new_state is `FSTRANS_NORMAL`.

`fstrans_is_owner`(mp)
  Return `true` if the current thread is currently suspending the file system mp.
`fscow_establish`(mp, func, cookie)
  Establish a copy-on-write callback for the file system mp. The function func will be called for every buffer bp written through this file system as
  `func(cookie, bp, data_valid)`
  where data_valid is true if and only if the buffer bp has not yet been modified.

  May sleep.

`fscow_disestablish`(mp, func, cookie)
  Disestablish a copy-on-write callback established with `fscow_establish`().

  May sleep.

`fscow_run`(bp, data_valid)
  Run all copy-on-write callbacks established for the file system this buffer belongs to, if they have not already been run for this buffer. If data_valid is `true` the buffer data has not yet been modified.

  May sleep.

# EXAMPLES

The following is an example of a file system suspend operation.

    int
    xxx_suspendctl(struct mount *mp, int cmd)
    {
    	int error;

    	switch (cmd) {
    	case SUSPEND_SUSPEND:
    		error = fstrans_setstate(mp, FSTRANS_SUSPENDING);
    		if (error)
    			return error;
    		return fstrans_setstate(mp, FSTRANS_SUSPENDED);

    	case SUSPEND_RESUME:
    		return fstrans_setstate(mp, FSTRANS_NORMAL);

    	default:
    		return EINVAL;
    	}
    }

This is an example of a file system operation.

    int
    xxx_create(void *v)
    {
    	struct vop_create_args *ap = v;
    	struct mount *mp = ap->a_dvp->v_mount;
    	int error;

    	fstrans_start(mp);

    	/* Actually create the node. */

    	fstrans_done(mp);

    	return 0;
    }

# CODE REFERENCES

The `fstrans` subsystem is implemented in the file sys/kern/vfs_trans.c.

# SEE ALSO

vfs_resume(9), vfs_suspend(9)

# HISTORY

The `fstrans` subsystem appeared in NetBSD 5.0.

# AUTHORS

The `fstrans` subsystem was written by Jürgen Hannken-Illjes ⟨hannken@NetBSD.org⟩.

# BUGS

`fstrans` is useful only for temporary suspension — it does not help to permanently block file system operations for unmounting, because `fstrans_start`() cannot fail.

October 4, 2018 | NetBSD 9.2