.\" $NetBSD: fstrans.9,v 1.29 2018/10/05 16:21:22 uwe Exp $
.\"
.\" Copyright (c) 2007 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Juergen Hannken-Illjes.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd October 4, 2018
.Dt FSTRANS 9
.Os
.Sh NAME
.Nm fstrans ,
.Nm fstrans_setstate ,
.Nm fstrans_getstate ,
.Nm fstrans_start ,
.Nm fstrans_start_nowait ,
.Nm fstrans_start_lazy ,
.Nm fstrans_done ,
.Nm fstrans_is_owner ,
.Nm fscow_establish ,
.Nm fscow_disestablish ,
.Nm fscow_run
.Nd file system suspension helper subsystem
.Sh SYNOPSIS
.In sys/mount.h
.In sys/fstrans.h
.Ft void
.Fn fstrans_start "struct mount *mp"
.Ft int
.Fn fstrans_start_nowait "struct mount *mp"
.Ft void
.Fn fstrans_start_lazy "struct mount *mp"
.Ft void
.Fn fstrans_done "struct mount *mp"
.Ft int
.Fn fstrans_setstate "struct mount *mp" "enum fstrans_state new_state"
.Ft "enum fstrans_state"
.Fn fstrans_getstate "struct mount *mp"
.Ft int
.Fn fstrans_is_owner "struct mount *mp"
.Ft int
.Fn fscow_establish "struct mount *mp" \
"int (*func)(void *, struct buf *, bool)" "void *cookie"
.Ft int
.Fn fscow_disestablish "struct mount *mp" \
"int (*func)(void *, struct buf *, bool)" "void *cookie"
.Ft int
.Fn fscow_run "struct buf *bp" "bool data_valid"
.Sh DESCRIPTION
The
.Nm
subsystem assists file system suspension and copy-on-write snapshots.
.Pp
The file system's normal operations, such as its
.Xr vnodeops 9 ,
must be bracketed by
.Fn fstrans_start
and
.Fn fstrans_done
in a
.Em shared
transaction, which is blocked by suspending the file system and while
it is suspended.
.Pp
Operations needed while suspending the file system must be bracketed by
.Fn fstrans_start_lazy
and
.Fn fstrans_done
in a
.Em lazy
transaction, which is allowed while suspending the file system, but
blocked while the file system is suspended.
.Pp
Transactions are per-thread and nestable: if a thread is already in a
transaction, it can enter another transaction without blocking.
Each
.Fn fstrans_start
must be paired with
.Fn fstrans_done .
Transactions for multiple distinct mount points may not be nested.
.Pp
The file system's
.Xr VFS_SUSPENDCTL 9
method can use
.Fn fstrans_setstate
to:
.Bl -dash
.It
enter the
.Dv FSTRANS_SUSPENDING
state to suspend all normal operations but allow lazy transactions,
.It
enter the
.Dv FSTRANS_SUSPENDED
state to suspend all operations, and
.It
restore to the
.Dv FSTRANS_NORMAL
state to resume all operations.
.El
.Pp
A file system supporting
.Nm
may establish a copy-on-write callback with
.Fn fscow_establish .
The copy-on-write callback will be called every time a buffer is
written to a block device with
.Fn VOP_STRATEGY
and every time a buffer is read into the
.Xr buffercache 9
with
.Dv B_MODIFY
set indicating the caller's intent to modify it.
Anyone modifying a buffer may additionally use
.Fn fscow_run
to explicitly invoke the established callback.
The copy-on-write callback must be disestablished with
.Fn fscow_disestablish
when the file system is done with it.
.Sh FUNCTIONS
.Bl -tag -width abcd
.It Fn fstrans_start "mp"
Enter a transaction on the file system
.Fa 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.
.Pp
If the file system is suspended, wait until it is resumed.
.Pp
However, if the current thread is already in a transaction on
.Fa mp ,
.Fn fstrans_start
will enter a nested transaction and return immediately without
waiting.
.Pp
May sleep.
.It Fn fstrans_start_nowait "mp"
Like
.Fn fstrans_start ,
but return
.Er EBUSY
immediately if transactions are blocked in its current state.
.Pp
May sleep nevertheless on internal locks.
.It Fn fstrans_start_lazy "mp"
Like
.Fn fstrans_start ,
but will not block while suspending.
.Pp
May sleep.
.It Fn fstrans_done "mp"
End the current transaction on
.Fa mp .
.It Fn fstrans_getstate "mp"
Return the current state of the file system
.Fa mp .
.Pp
Must be called within a transaction for the answer to be stable.
.It Fn fstrans_setstate "mp" "new_state"
Change the state of the file system
.Fa mp
to
.Fa new_state ,
and wait for all transactions not allowed in
.Fa new_state
to complete.
.Bl -tag -width "Dv FSTRANS_SUSPENDING"
.It Dv FSTRANS_NORMAL
Allow all transactions.
.It Dv FSTRANS_SUSPENDING
Block
.Dv FSTRANS_SHARED
transactions but allow
.Dv FSTRANS_LAZY
transactions.
.It Dv FSTRANS_SUSPENDED
Block all transactions.
.El
.Pp
A thread that changes a file system to a state other than
.Dv FSTRANS_NORMAL
enters a transaction for the purposes of
.Fn fstrans_getstate
until it changes state back to
.Dv FSTRANS_NORMAL .
.Pp
Additionally, a thread that changes a file system to a state other than
.Dv FSTRANS_NORMAL
acquires an exclusive lock on the file system state, so that
.Fn 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
.Dv FSTRANS_NORMAL .
.Pp
May sleep, and may be interrupted by a signal.
On success, return zero.
On failure, restore the file system to the
.Dv FSTRANS_NORMAL
state and return an error code.
.Fn fstrans_setstate
never fails if
.Fa new_state
is
.Dv FSTRANS_NORMAL .
.It Fn fstrans_is_owner "mp"
Return
.Dv true
if the current thread is currently suspending the file system
.Fa mp .
.It Fn fscow_establish "mp" "func" "cookie"
Establish a copy-on-write callback for the file system
.Fa mp .
The function
.Fa func
will be called for every buffer
.Fa bp
written through this file system as
.Dl Fa func Ns ( Fa cookie , Fa bp , Fa data_valid )
where
.Fa data_valid
is true if and only if the buffer
.Fa bp
has not yet been modified.
.Pp
May sleep.
.It Fn fscow_disestablish "mp" "func" "cookie"
Disestablish a copy-on-write callback established with
.Fn fscow_establish .
.Pp
May sleep.
.It Fn 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
.Fa data_valid
is
.Dv true
the buffer data has not yet been modified.
.Pp
May sleep.
.El
.Sh EXAMPLES
The following is an example of a file system suspend operation.
.Bd -literal
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;
}
}
.Ed
.Pp
This is an example of a file system operation.
.Bd -literal
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;
}
.Ed
.Sh CODE REFERENCES
The
.Nm
subsystem is implemented in the file
.Pa sys/kern/vfs_trans.c .
.Sh SEE ALSO
.Xr vfs_resume 9 ,
.Xr vfs_suspend 9
.Sh HISTORY
The
.Nm
subsystem appeared in
.Nx 5.0 .
.Sh AUTHORS
The
.Nm
subsystem was written by
.An J\(:urgen Hannken-Illjes
.Aq hannken@NetBSD.org .
.Sh BUGS
.Nm
is useful only for temporary suspension \(em it does not help to
permanently block file system operations for unmounting, because
.Fn fstrans_start
cannot fail.