2004-10-29 09:56:56 +00:00
|
|
|
/*-
|
2017-11-27 15:17:37 +00:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
|
|
|
*
|
2004-10-29 09:56:56 +00:00
|
|
|
* Copyright (c) 2004 Poul-Henning Kamp
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* 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 AUTHOR 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 AUTHOR 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
|
|
|
#include <sys/bio.h>
|
|
|
|
#include <sys/kernel.h>
|
2011-11-02 09:24:59 +00:00
|
|
|
#include <sys/lock.h>
|
2004-10-29 09:56:56 +00:00
|
|
|
#include <sys/malloc.h>
|
2011-11-02 09:24:59 +00:00
|
|
|
#include <sys/mutex.h>
|
2019-08-07 19:28:35 +00:00
|
|
|
#include <sys/sbuf.h>
|
2004-10-29 09:56:56 +00:00
|
|
|
#include <sys/vnode.h>
|
2012-10-22 17:50:54 +00:00
|
|
|
#include <sys/mount.h>
|
2004-10-29 09:56:56 +00:00
|
|
|
|
|
|
|
#include <geom/geom.h>
|
|
|
|
#include <geom/geom_vfs.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* subroutines for use by filesystems.
|
|
|
|
*
|
|
|
|
* XXX: should maybe live somewhere else ?
|
|
|
|
*/
|
|
|
|
#include <sys/buf.h>
|
|
|
|
|
2011-11-02 09:24:59 +00:00
|
|
|
struct g_vfs_softc {
|
|
|
|
struct mtx sc_mtx;
|
|
|
|
struct bufobj *sc_bo;
|
|
|
|
int sc_active;
|
|
|
|
int sc_orphaned;
|
This commit enables a UFS filesystem to do a forcible unmount when
the underlying media fails or becomes inaccessible. For example
when a USB flash memory card hosting a UFS filesystem is unplugged.
The strategy for handling disk I/O errors when soft updates are
enabled is to stop writing to the disk of the affected file system
but continue to accept I/O requests and report that all future
writes by the file system to that disk actually succeed. Then
initiate an asynchronous forced unmount of the affected file system.
There are two cases for disk I/O errors:
- ENXIO, which means that this disk is gone and the lower layers
of the storage stack already guarantee that no future I/O to
this disk will succeed.
- EIO (or most other errors), which means that this particular
I/O request has failed but subsequent I/O requests to this
disk might still succeed.
For ENXIO, we can just clear the error and continue, because we
know that the file system cannot affect the on-disk state after we
see this error. For EIO or other errors, we arrange for the geom_vfs
layer to reject all future I/O requests with ENXIO just like is
done when the geom_vfs is orphaned. In both cases, the file system
code can just clear the error and proceed with the forcible unmount.
This new treatment of I/O errors is needed for writes of any buffer
that is involved in a dependency. Most dependencies are described
by a structure attached to the buffer's b_dep field. But some are
created and processed as a result of the completion of the dependencies
attached to the buffer.
Clearing of some dependencies require a read. For example if there
is a dependency that requires an inode to be written, the disk block
containing that inode must be read, the updated inode copied into
place in that buffer, and the buffer then written back to disk.
Often the needed buffer is already in memory and can be used. But
if it needs to be read from the disk, the read will fail, so we
fabricate a buffer full of zeroes and pretend that the read succeeded.
This zero'ed buffer can be updated and written back to disk.
The only case where a buffer full of zeros causes the code to do
the wrong thing is when reading an inode buffer containing an inode
that still has an inode dependency in memory that will reinitialize
the effective link count (i_effnlink) based on the actual link count
(i_nlink) that we read. To handle this case we now store the i_nlink
value that we wrote in the inode dependency so that it can be
restored into the zero'ed buffer thus keeping the tracking of the
inode link count consistent.
Because applications depend on knowing when an attempt to write
their data to stable storage has failed, the fsync(2) and msync(2)
system calls need to return errors if data fails to be written to
stable storage. So these operations return ENXIO for every call
made on files in a file system where we have otherwise been ignoring
I/O errors.
Coauthered by: mckusick
Reviewed by: kib
Tested by: Peter Holm
Approved by: mckusick (mentor)
Sponsored by: Netflix
Differential Revision: https://reviews.freebsd.org/D24088
2020-05-25 23:47:31 +00:00
|
|
|
int sc_enxio_active;
|
2011-11-02 09:24:59 +00:00
|
|
|
};
|
|
|
|
|
2004-10-29 09:56:56 +00:00
|
|
|
static struct buf_ops __g_vfs_bufops = {
|
|
|
|
.bop_name = "GEOM_VFS",
|
|
|
|
.bop_write = bufwrite,
|
|
|
|
.bop_strategy = g_vfs_strategy,
|
2005-01-11 10:43:08 +00:00
|
|
|
.bop_sync = bufsync,
|
Cylinder group bitmaps and blocks containing inode for a snapshot
file are after snaplock, while other ffs device buffers are before
snaplock in global lock order. By itself, this could cause deadlock
when bdwrite() tries to flush dirty buffers on snapshotted ffs. If,
during the flush, COW activity for snapshot needs to allocate block
and ffs_alloccg() selects the cylinder group that is being written
by bdwrite(), then kernel would panic due to recursive buffer lock
acquision.
Avoid dealing with buffers in bdwrite() that are from other side of
snaplock divisor in the lock order then the buffer being written. Add
new BOP, bop_bdwrite(), to do dirty buffer flushing for same vnode in
the bdwrite(). Default implementation, bufbdflush(), refactors the code
from bdwrite(). For ffs device buffers, specialized implementation is
used.
Reviewed by: tegge, jeff, Russell Cattelan (cattelan xfs org, xfs changes)
Tested by: Peter Holm
X-MFC after: 3 weeks (if ever: it changes ABI)
2007-01-23 10:01:19 +00:00
|
|
|
.bop_bdflush = bufbdflush
|
2004-10-29 09:56:56 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct buf_ops *g_vfs_bufops = &__g_vfs_bufops;
|
|
|
|
|
2005-02-10 12:10:35 +00:00
|
|
|
static g_orphan_t g_vfs_orphan;
|
|
|
|
|
2004-10-29 09:56:56 +00:00
|
|
|
static struct g_class g_vfs_class = {
|
|
|
|
.name = "VFS",
|
|
|
|
.version = G_VERSION,
|
|
|
|
.orphan = g_vfs_orphan,
|
|
|
|
};
|
|
|
|
|
|
|
|
DECLARE_GEOM_CLASS(g_vfs_class, g_vfs);
|
|
|
|
|
2011-11-02 09:24:59 +00:00
|
|
|
static void
|
|
|
|
g_vfs_destroy(void *arg, int flags __unused)
|
|
|
|
{
|
|
|
|
struct g_consumer *cp;
|
|
|
|
|
|
|
|
g_topology_assert();
|
|
|
|
cp = arg;
|
|
|
|
if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
|
|
|
|
g_access(cp, -cp->acr, -cp->acw, -cp->ace);
|
|
|
|
g_detach(cp);
|
|
|
|
if (cp->geom->softc == NULL)
|
|
|
|
g_wither_geom(cp->geom, ENXIO);
|
|
|
|
}
|
|
|
|
|
2004-10-29 09:56:56 +00:00
|
|
|
static void
|
|
|
|
g_vfs_done(struct bio *bip)
|
|
|
|
{
|
2011-11-02 09:24:59 +00:00
|
|
|
struct g_consumer *cp;
|
|
|
|
struct g_vfs_softc *sc;
|
2004-10-29 09:56:56 +00:00
|
|
|
struct buf *bp;
|
2012-10-22 17:50:54 +00:00
|
|
|
int destroy;
|
2012-03-28 20:49:11 +00:00
|
|
|
struct mount *mp;
|
|
|
|
struct vnode *vp;
|
2012-04-08 06:20:21 +00:00
|
|
|
struct cdev *cdevp;
|
2012-03-28 20:49:11 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Collect statistics on synchronous and asynchronous read
|
|
|
|
* and write counts for disks that have associated filesystems.
|
|
|
|
*/
|
|
|
|
bp = bip->bio_caller2;
|
|
|
|
vp = bp->b_vp;
|
Merge GEOM direct dispatch changes from the projects/camlock branch.
When safety requirements are met, it allows to avoid passing I/O requests
to GEOM g_up/g_down thread, executing them directly in the caller context.
That allows to avoid CPU bottlenecks in g_up/g_down threads, plus avoid
several context switches per I/O.
The defined now safety requirements are:
- caller should not hold any locks and should be reenterable;
- callee should not depend on GEOM dual-threaded concurency semantics;
- on the way down, if request is unmapped while callee doesn't support it,
the context should be sleepable;
- kernel thread stack usage should be below 50%.
To keep compatibility with GEOM classes not meeting above requirements
new provider and consumer flags added:
- G_CF_DIRECT_SEND -- consumer code meets caller requirements (request);
- G_CF_DIRECT_RECEIVE -- consumer code meets callee requirements (done);
- G_PF_DIRECT_SEND -- provider code meets caller requirements (done);
- G_PF_DIRECT_RECEIVE -- provider code meets callee requirements (request).
Capable GEOM class can set them, allowing direct dispatch in cases where
it is safe. If any of requirements are not met, request is queued to
g_up or g_down thread same as before.
Such GEOM classes were reviewed and updated to support direct dispatch:
CONCAT, DEV, DISK, GATE, MD, MIRROR, MULTIPATH, NOP, PART, RAID, STRIPE,
VFS, ZERO, ZFS::VDEV, ZFS::ZVOL, all classes based on g_slice KPI (LABEL,
MAP, FLASHMAP, etc).
To declare direct completion capability disk(9) KPI got new flag equivalent
to G_PF_DIRECT_SEND -- DISKFLAG_DIRECT_COMPLETION. da(4) and ada(4) disk
drivers got it set now thanks to earlier CAM locking work.
This change more then twice increases peak block storage performance on
systems with manu CPUs, together with earlier CAM locking changes reaching
more then 1 million IOPS (512 byte raw reads from 16 SATA SSDs on 4 HBAs to
256 user-level threads).
Sponsored by: iXsystems, Inc.
MFC after: 2 months
2013-10-22 08:22:19 +00:00
|
|
|
if (vp != NULL) {
|
2012-04-08 06:20:21 +00:00
|
|
|
/*
|
|
|
|
* If not a disk vnode, use its associated mount point
|
|
|
|
* otherwise use the mountpoint associated with the disk.
|
|
|
|
*/
|
|
|
|
VI_LOCK(vp);
|
|
|
|
if (vp->v_type != VCHR ||
|
|
|
|
(cdevp = vp->v_rdev) == NULL ||
|
|
|
|
cdevp->si_devsw == NULL ||
|
|
|
|
(cdevp->si_devsw->d_flags & D_DISK) == 0)
|
|
|
|
mp = vp->v_mount;
|
|
|
|
else
|
|
|
|
mp = cdevp->si_mountpt;
|
Merge GEOM direct dispatch changes from the projects/camlock branch.
When safety requirements are met, it allows to avoid passing I/O requests
to GEOM g_up/g_down thread, executing them directly in the caller context.
That allows to avoid CPU bottlenecks in g_up/g_down threads, plus avoid
several context switches per I/O.
The defined now safety requirements are:
- caller should not hold any locks and should be reenterable;
- callee should not depend on GEOM dual-threaded concurency semantics;
- on the way down, if request is unmapped while callee doesn't support it,
the context should be sleepable;
- kernel thread stack usage should be below 50%.
To keep compatibility with GEOM classes not meeting above requirements
new provider and consumer flags added:
- G_CF_DIRECT_SEND -- consumer code meets caller requirements (request);
- G_CF_DIRECT_RECEIVE -- consumer code meets callee requirements (done);
- G_PF_DIRECT_SEND -- provider code meets caller requirements (done);
- G_PF_DIRECT_RECEIVE -- provider code meets callee requirements (request).
Capable GEOM class can set them, allowing direct dispatch in cases where
it is safe. If any of requirements are not met, request is queued to
g_up or g_down thread same as before.
Such GEOM classes were reviewed and updated to support direct dispatch:
CONCAT, DEV, DISK, GATE, MD, MIRROR, MULTIPATH, NOP, PART, RAID, STRIPE,
VFS, ZERO, ZFS::VDEV, ZFS::ZVOL, all classes based on g_slice KPI (LABEL,
MAP, FLASHMAP, etc).
To declare direct completion capability disk(9) KPI got new flag equivalent
to G_PF_DIRECT_SEND -- DISKFLAG_DIRECT_COMPLETION. da(4) and ada(4) disk
drivers got it set now thanks to earlier CAM locking work.
This change more then twice increases peak block storage performance on
systems with manu CPUs, together with earlier CAM locking changes reaching
more then 1 million IOPS (512 byte raw reads from 16 SATA SSDs on 4 HBAs to
256 user-level threads).
Sponsored by: iXsystems, Inc.
MFC after: 2 months
2013-10-22 08:22:19 +00:00
|
|
|
if (mp != NULL) {
|
|
|
|
if (bp->b_iocmd == BIO_READ) {
|
|
|
|
if (LK_HOLDER(bp->b_lock.lk_lock) == LK_KERNPROC)
|
|
|
|
mp->mnt_stat.f_asyncreads++;
|
|
|
|
else
|
|
|
|
mp->mnt_stat.f_syncreads++;
|
|
|
|
} else if (bp->b_iocmd == BIO_WRITE) {
|
|
|
|
if (LK_HOLDER(bp->b_lock.lk_lock) == LK_KERNPROC)
|
|
|
|
mp->mnt_stat.f_asyncwrites++;
|
|
|
|
else
|
|
|
|
mp->mnt_stat.f_syncwrites++;
|
|
|
|
}
|
2012-03-28 20:49:11 +00:00
|
|
|
}
|
Merge GEOM direct dispatch changes from the projects/camlock branch.
When safety requirements are met, it allows to avoid passing I/O requests
to GEOM g_up/g_down thread, executing them directly in the caller context.
That allows to avoid CPU bottlenecks in g_up/g_down threads, plus avoid
several context switches per I/O.
The defined now safety requirements are:
- caller should not hold any locks and should be reenterable;
- callee should not depend on GEOM dual-threaded concurency semantics;
- on the way down, if request is unmapped while callee doesn't support it,
the context should be sleepable;
- kernel thread stack usage should be below 50%.
To keep compatibility with GEOM classes not meeting above requirements
new provider and consumer flags added:
- G_CF_DIRECT_SEND -- consumer code meets caller requirements (request);
- G_CF_DIRECT_RECEIVE -- consumer code meets callee requirements (done);
- G_PF_DIRECT_SEND -- provider code meets caller requirements (done);
- G_PF_DIRECT_RECEIVE -- provider code meets callee requirements (request).
Capable GEOM class can set them, allowing direct dispatch in cases where
it is safe. If any of requirements are not met, request is queued to
g_up or g_down thread same as before.
Such GEOM classes were reviewed and updated to support direct dispatch:
CONCAT, DEV, DISK, GATE, MD, MIRROR, MULTIPATH, NOP, PART, RAID, STRIPE,
VFS, ZERO, ZFS::VDEV, ZFS::ZVOL, all classes based on g_slice KPI (LABEL,
MAP, FLASHMAP, etc).
To declare direct completion capability disk(9) KPI got new flag equivalent
to G_PF_DIRECT_SEND -- DISKFLAG_DIRECT_COMPLETION. da(4) and ada(4) disk
drivers got it set now thanks to earlier CAM locking work.
This change more then twice increases peak block storage performance on
systems with manu CPUs, together with earlier CAM locking changes reaching
more then 1 million IOPS (512 byte raw reads from 16 SATA SSDs on 4 HBAs to
256 user-level threads).
Sponsored by: iXsystems, Inc.
MFC after: 2 months
2013-10-22 08:22:19 +00:00
|
|
|
VI_UNLOCK(vp);
|
2012-03-28 20:49:11 +00:00
|
|
|
}
|
2009-01-11 13:51:04 +00:00
|
|
|
|
2011-11-02 09:24:59 +00:00
|
|
|
cp = bip->bio_from;
|
|
|
|
sc = cp->geom->softc;
|
This commit enables a UFS filesystem to do a forcible unmount when
the underlying media fails or becomes inaccessible. For example
when a USB flash memory card hosting a UFS filesystem is unplugged.
The strategy for handling disk I/O errors when soft updates are
enabled is to stop writing to the disk of the affected file system
but continue to accept I/O requests and report that all future
writes by the file system to that disk actually succeed. Then
initiate an asynchronous forced unmount of the affected file system.
There are two cases for disk I/O errors:
- ENXIO, which means that this disk is gone and the lower layers
of the storage stack already guarantee that no future I/O to
this disk will succeed.
- EIO (or most other errors), which means that this particular
I/O request has failed but subsequent I/O requests to this
disk might still succeed.
For ENXIO, we can just clear the error and continue, because we
know that the file system cannot affect the on-disk state after we
see this error. For EIO or other errors, we arrange for the geom_vfs
layer to reject all future I/O requests with ENXIO just like is
done when the geom_vfs is orphaned. In both cases, the file system
code can just clear the error and proceed with the forcible unmount.
This new treatment of I/O errors is needed for writes of any buffer
that is involved in a dependency. Most dependencies are described
by a structure attached to the buffer's b_dep field. But some are
created and processed as a result of the completion of the dependencies
attached to the buffer.
Clearing of some dependencies require a read. For example if there
is a dependency that requires an inode to be written, the disk block
containing that inode must be read, the updated inode copied into
place in that buffer, and the buffer then written back to disk.
Often the needed buffer is already in memory and can be used. But
if it needs to be read from the disk, the read will fail, so we
fabricate a buffer full of zeroes and pretend that the read succeeded.
This zero'ed buffer can be updated and written back to disk.
The only case where a buffer full of zeros causes the code to do
the wrong thing is when reading an inode buffer containing an inode
that still has an inode dependency in memory that will reinitialize
the effective link count (i_effnlink) based on the actual link count
(i_nlink) that we read. To handle this case we now store the i_nlink
value that we wrote in the inode dependency so that it can be
restored into the zero'ed buffer thus keeping the tracking of the
inode link count consistent.
Because applications depend on knowing when an attempt to write
their data to stable storage has failed, the fsync(2) and msync(2)
system calls need to return errors if data fails to be written to
stable storage. So these operations return ENXIO for every call
made on files in a file system where we have otherwise been ignoring
I/O errors.
Coauthered by: mckusick
Reviewed by: kib
Tested by: Peter Holm
Approved by: mckusick (mentor)
Sponsored by: Netflix
Differential Revision: https://reviews.freebsd.org/D24088
2020-05-25 23:47:31 +00:00
|
|
|
if (bip->bio_error != 0 && bip->bio_error != EOPNOTSUPP) {
|
|
|
|
if ((bp->b_xflags & BX_CVTENXIO) != 0)
|
|
|
|
sc->sc_enxio_active = 1;
|
|
|
|
if (sc->sc_enxio_active)
|
|
|
|
bip->bio_error = ENXIO;
|
2019-08-07 19:28:35 +00:00
|
|
|
g_print_bio("g_vfs_done():", bip, "error = %d",
|
|
|
|
bip->bio_error);
|
This commit enables a UFS filesystem to do a forcible unmount when
the underlying media fails or becomes inaccessible. For example
when a USB flash memory card hosting a UFS filesystem is unplugged.
The strategy for handling disk I/O errors when soft updates are
enabled is to stop writing to the disk of the affected file system
but continue to accept I/O requests and report that all future
writes by the file system to that disk actually succeed. Then
initiate an asynchronous forced unmount of the affected file system.
There are two cases for disk I/O errors:
- ENXIO, which means that this disk is gone and the lower layers
of the storage stack already guarantee that no future I/O to
this disk will succeed.
- EIO (or most other errors), which means that this particular
I/O request has failed but subsequent I/O requests to this
disk might still succeed.
For ENXIO, we can just clear the error and continue, because we
know that the file system cannot affect the on-disk state after we
see this error. For EIO or other errors, we arrange for the geom_vfs
layer to reject all future I/O requests with ENXIO just like is
done when the geom_vfs is orphaned. In both cases, the file system
code can just clear the error and proceed with the forcible unmount.
This new treatment of I/O errors is needed for writes of any buffer
that is involved in a dependency. Most dependencies are described
by a structure attached to the buffer's b_dep field. But some are
created and processed as a result of the completion of the dependencies
attached to the buffer.
Clearing of some dependencies require a read. For example if there
is a dependency that requires an inode to be written, the disk block
containing that inode must be read, the updated inode copied into
place in that buffer, and the buffer then written back to disk.
Often the needed buffer is already in memory and can be used. But
if it needs to be read from the disk, the read will fail, so we
fabricate a buffer full of zeroes and pretend that the read succeeded.
This zero'ed buffer can be updated and written back to disk.
The only case where a buffer full of zeros causes the code to do
the wrong thing is when reading an inode buffer containing an inode
that still has an inode dependency in memory that will reinitialize
the effective link count (i_effnlink) based on the actual link count
(i_nlink) that we read. To handle this case we now store the i_nlink
value that we wrote in the inode dependency so that it can be
restored into the zero'ed buffer thus keeping the tracking of the
inode link count consistent.
Because applications depend on knowing when an attempt to write
their data to stable storage has failed, the fsync(2) and msync(2)
system calls need to return errors if data fails to be written to
stable storage. So these operations return ENXIO for every call
made on files in a file system where we have otherwise been ignoring
I/O errors.
Coauthered by: mckusick
Reviewed by: kib
Tested by: Peter Holm
Approved by: mckusick (mentor)
Sponsored by: Netflix
Differential Revision: https://reviews.freebsd.org/D24088
2020-05-25 23:47:31 +00:00
|
|
|
}
|
2004-10-29 09:56:56 +00:00
|
|
|
bp->b_error = bip->bio_error;
|
|
|
|
bp->b_ioflags = bip->bio_flags;
|
|
|
|
if (bip->bio_error)
|
|
|
|
bp->b_ioflags |= BIO_ERROR;
|
|
|
|
bp->b_resid = bp->b_bcount - bip->bio_completed;
|
|
|
|
g_destroy_bio(bip);
|
2011-11-02 09:24:59 +00:00
|
|
|
|
|
|
|
mtx_lock(&sc->sc_mtx);
|
|
|
|
destroy = ((--sc->sc_active) == 0 && sc->sc_orphaned);
|
|
|
|
mtx_unlock(&sc->sc_mtx);
|
|
|
|
if (destroy)
|
|
|
|
g_post_event(g_vfs_destroy, cp, M_WAITOK, NULL);
|
|
|
|
|
2004-10-29 09:56:56 +00:00
|
|
|
bufdone(bp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
g_vfs_strategy(struct bufobj *bo, struct buf *bp)
|
|
|
|
{
|
2011-11-02 09:24:59 +00:00
|
|
|
struct g_vfs_softc *sc;
|
2004-10-29 09:56:56 +00:00
|
|
|
struct g_consumer *cp;
|
|
|
|
struct bio *bip;
|
|
|
|
|
|
|
|
cp = bo->bo_private;
|
2011-11-02 09:24:59 +00:00
|
|
|
sc = cp->geom->softc;
|
2004-10-29 09:56:56 +00:00
|
|
|
|
2008-12-16 17:04:52 +00:00
|
|
|
/*
|
2017-05-18 08:25:07 +00:00
|
|
|
* If the provider has orphaned us, just return ENXIO.
|
2008-12-16 17:04:52 +00:00
|
|
|
*/
|
2011-11-02 09:24:59 +00:00
|
|
|
mtx_lock(&sc->sc_mtx);
|
This commit enables a UFS filesystem to do a forcible unmount when
the underlying media fails or becomes inaccessible. For example
when a USB flash memory card hosting a UFS filesystem is unplugged.
The strategy for handling disk I/O errors when soft updates are
enabled is to stop writing to the disk of the affected file system
but continue to accept I/O requests and report that all future
writes by the file system to that disk actually succeed. Then
initiate an asynchronous forced unmount of the affected file system.
There are two cases for disk I/O errors:
- ENXIO, which means that this disk is gone and the lower layers
of the storage stack already guarantee that no future I/O to
this disk will succeed.
- EIO (or most other errors), which means that this particular
I/O request has failed but subsequent I/O requests to this
disk might still succeed.
For ENXIO, we can just clear the error and continue, because we
know that the file system cannot affect the on-disk state after we
see this error. For EIO or other errors, we arrange for the geom_vfs
layer to reject all future I/O requests with ENXIO just like is
done when the geom_vfs is orphaned. In both cases, the file system
code can just clear the error and proceed with the forcible unmount.
This new treatment of I/O errors is needed for writes of any buffer
that is involved in a dependency. Most dependencies are described
by a structure attached to the buffer's b_dep field. But some are
created and processed as a result of the completion of the dependencies
attached to the buffer.
Clearing of some dependencies require a read. For example if there
is a dependency that requires an inode to be written, the disk block
containing that inode must be read, the updated inode copied into
place in that buffer, and the buffer then written back to disk.
Often the needed buffer is already in memory and can be used. But
if it needs to be read from the disk, the read will fail, so we
fabricate a buffer full of zeroes and pretend that the read succeeded.
This zero'ed buffer can be updated and written back to disk.
The only case where a buffer full of zeros causes the code to do
the wrong thing is when reading an inode buffer containing an inode
that still has an inode dependency in memory that will reinitialize
the effective link count (i_effnlink) based on the actual link count
(i_nlink) that we read. To handle this case we now store the i_nlink
value that we wrote in the inode dependency so that it can be
restored into the zero'ed buffer thus keeping the tracking of the
inode link count consistent.
Because applications depend on knowing when an attempt to write
their data to stable storage has failed, the fsync(2) and msync(2)
system calls need to return errors if data fails to be written to
stable storage. So these operations return ENXIO for every call
made on files in a file system where we have otherwise been ignoring
I/O errors.
Coauthered by: mckusick
Reviewed by: kib
Tested by: Peter Holm
Approved by: mckusick (mentor)
Sponsored by: Netflix
Differential Revision: https://reviews.freebsd.org/D24088
2020-05-25 23:47:31 +00:00
|
|
|
if (sc->sc_orphaned || sc->sc_enxio_active) {
|
2011-11-02 09:24:59 +00:00
|
|
|
mtx_unlock(&sc->sc_mtx);
|
2008-12-16 17:04:52 +00:00
|
|
|
bp->b_error = ENXIO;
|
|
|
|
bp->b_ioflags |= BIO_ERROR;
|
|
|
|
bufdone(bp);
|
|
|
|
return;
|
|
|
|
}
|
2011-11-02 09:24:59 +00:00
|
|
|
sc->sc_active++;
|
|
|
|
mtx_unlock(&sc->sc_mtx);
|
2008-12-16 17:04:52 +00:00
|
|
|
|
2004-10-29 09:56:56 +00:00
|
|
|
bip = g_alloc_bio();
|
|
|
|
bip->bio_cmd = bp->b_iocmd;
|
|
|
|
bip->bio_offset = bp->b_iooffset;
|
|
|
|
bip->bio_length = bp->b_bcount;
|
Implement the concept of the unmapped VMIO buffers, i.e. buffers which
do not map the b_pages pages into buffer_map KVA. The use of the
unmapped buffers eliminate the need to perform TLB shootdown for
mapping on the buffer creation and reuse, greatly reducing the amount
of IPIs for shootdown on big-SMP machines and eliminating up to 25-30%
of the system time on i/o intensive workloads.
The unmapped buffer should be explicitely requested by the GB_UNMAPPED
flag by the consumer. For unmapped buffer, no KVA reservation is
performed at all. The consumer might request unmapped buffer which
does have a KVA reserve, to manually map it without recursing into
buffer cache and blocking, with the GB_KVAALLOC flag.
When the mapped buffer is requested and unmapped buffer already
exists, the cache performs an upgrade, possibly reusing the KVA
reservation.
Unmapped buffer is translated into unmapped bio in g_vfs_strategy().
Unmapped bio carry a pointer to the vm_page_t array, offset and length
instead of the data pointer. The provider which processes the bio
should explicitely specify a readiness to accept unmapped bio,
otherwise g_down geom thread performs the transient upgrade of the bio
request by mapping the pages into the new bio_transient_map KVA
submap.
The bio_transient_map submap claims up to 10% of the buffer map, and
the total buffer_map + bio_transient_map KVA usage stays the
same. Still, it could be manually tuned by kern.bio_transient_maxcnt
tunable, in the units of the transient mappings. Eventually, the
bio_transient_map could be removed after all geom classes and drivers
can accept unmapped i/o requests.
Unmapped support can be turned off by the vfs.unmapped_buf_allowed
tunable, disabling which makes the buffer (or cluster) creation
requests to ignore GB_UNMAPPED and GB_KVAALLOC flags. Unmapped
buffers are only enabled by default on the architectures where
pmap_copy_page() was implemented and tested.
In the rework, filesystem metadata is not the subject to maxbufspace
limit anymore. Since the metadata buffers are always mapped, the
buffers still have to fit into the buffer map, which provides a
reasonable (but practically unreachable) upper bound on it. The
non-metadata buffer allocations, both mapped and unmapped, is
accounted against maxbufspace, as before. Effectively, this means that
the maxbufspace is forced on mapped and unmapped buffers separately.
The pre-patch bufspace limiting code did not worked, because
buffer_map fragmentation does not allow the limit to be reached.
By Jeff Roberson request, the getnewbuf() function was split into
smaller single-purpose functions.
Sponsored by: The FreeBSD Foundation
Discussed with: jeff (previous version)
Tested by: pho, scottl (previous version), jhb, bf
MFC after: 2 weeks
2013-03-19 14:13:12 +00:00
|
|
|
bdata2bio(bp, bip);
|
|
|
|
if ((bp->b_flags & B_BARRIER) != 0) {
|
2013-02-16 14:51:30 +00:00
|
|
|
bip->bio_flags |= BIO_ORDERED;
|
|
|
|
bp->b_flags &= ~B_BARRIER;
|
|
|
|
}
|
2020-01-17 01:16:19 +00:00
|
|
|
if (bp->b_iocmd == BIO_SPEEDUP)
|
|
|
|
bip->bio_flags |= bp->b_ioflags;
|
Implement the concept of the unmapped VMIO buffers, i.e. buffers which
do not map the b_pages pages into buffer_map KVA. The use of the
unmapped buffers eliminate the need to perform TLB shootdown for
mapping on the buffer creation and reuse, greatly reducing the amount
of IPIs for shootdown on big-SMP machines and eliminating up to 25-30%
of the system time on i/o intensive workloads.
The unmapped buffer should be explicitely requested by the GB_UNMAPPED
flag by the consumer. For unmapped buffer, no KVA reservation is
performed at all. The consumer might request unmapped buffer which
does have a KVA reserve, to manually map it without recursing into
buffer cache and blocking, with the GB_KVAALLOC flag.
When the mapped buffer is requested and unmapped buffer already
exists, the cache performs an upgrade, possibly reusing the KVA
reservation.
Unmapped buffer is translated into unmapped bio in g_vfs_strategy().
Unmapped bio carry a pointer to the vm_page_t array, offset and length
instead of the data pointer. The provider which processes the bio
should explicitely specify a readiness to accept unmapped bio,
otherwise g_down geom thread performs the transient upgrade of the bio
request by mapping the pages into the new bio_transient_map KVA
submap.
The bio_transient_map submap claims up to 10% of the buffer map, and
the total buffer_map + bio_transient_map KVA usage stays the
same. Still, it could be manually tuned by kern.bio_transient_maxcnt
tunable, in the units of the transient mappings. Eventually, the
bio_transient_map could be removed after all geom classes and drivers
can accept unmapped i/o requests.
Unmapped support can be turned off by the vfs.unmapped_buf_allowed
tunable, disabling which makes the buffer (or cluster) creation
requests to ignore GB_UNMAPPED and GB_KVAALLOC flags. Unmapped
buffers are only enabled by default on the architectures where
pmap_copy_page() was implemented and tested.
In the rework, filesystem metadata is not the subject to maxbufspace
limit anymore. Since the metadata buffers are always mapped, the
buffers still have to fit into the buffer map, which provides a
reasonable (but practically unreachable) upper bound on it. The
non-metadata buffer allocations, both mapped and unmapped, is
accounted against maxbufspace, as before. Effectively, this means that
the maxbufspace is forced on mapped and unmapped buffers separately.
The pre-patch bufspace limiting code did not worked, because
buffer_map fragmentation does not allow the limit to be reached.
By Jeff Roberson request, the getnewbuf() function was split into
smaller single-purpose functions.
Sponsored by: The FreeBSD Foundation
Discussed with: jeff (previous version)
Tested by: pho, scottl (previous version), jhb, bf
MFC after: 2 weeks
2013-03-19 14:13:12 +00:00
|
|
|
bip->bio_done = g_vfs_done;
|
|
|
|
bip->bio_caller2 = bp;
|
2016-10-31 23:09:52 +00:00
|
|
|
#if defined(BUF_TRACKING) || defined(FULL_BUF_TRACKING)
|
|
|
|
buf_track(bp, __func__);
|
|
|
|
bip->bio_track_bp = bp;
|
|
|
|
#endif
|
2004-10-29 09:56:56 +00:00
|
|
|
g_io_request(bip, cp);
|
|
|
|
}
|
|
|
|
|
2005-02-10 12:10:35 +00:00
|
|
|
static void
|
2004-10-29 09:56:56 +00:00
|
|
|
g_vfs_orphan(struct g_consumer *cp)
|
|
|
|
{
|
2008-12-16 17:04:52 +00:00
|
|
|
struct g_geom *gp;
|
2011-11-02 09:24:59 +00:00
|
|
|
struct g_vfs_softc *sc;
|
|
|
|
int destroy;
|
2008-12-16 17:04:52 +00:00
|
|
|
|
|
|
|
g_topology_assert();
|
|
|
|
|
|
|
|
gp = cp->geom;
|
|
|
|
g_trace(G_T_TOPOLOGY, "g_vfs_orphan(%p(%s))", cp, gp->name);
|
2011-12-02 17:09:48 +00:00
|
|
|
sc = gp->softc;
|
|
|
|
if (sc == NULL)
|
|
|
|
return;
|
2011-11-02 09:24:59 +00:00
|
|
|
mtx_lock(&sc->sc_mtx);
|
|
|
|
sc->sc_orphaned = 1;
|
2012-07-29 20:04:09 +00:00
|
|
|
destroy = (sc->sc_active == 0);
|
2011-11-02 09:24:59 +00:00
|
|
|
mtx_unlock(&sc->sc_mtx);
|
|
|
|
if (destroy)
|
|
|
|
g_vfs_destroy(cp, 0);
|
2004-10-29 09:56:56 +00:00
|
|
|
|
|
|
|
/*
|
2009-01-11 13:51:04 +00:00
|
|
|
* Do not destroy the geom. Filesystem will do that during unmount.
|
2004-10-29 09:56:56 +00:00
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
g_vfs_open(struct vnode *vp, struct g_consumer **cpp, const char *fsname, int wr)
|
|
|
|
{
|
|
|
|
struct g_geom *gp;
|
|
|
|
struct g_provider *pp;
|
|
|
|
struct g_consumer *cp;
|
2011-11-02 09:24:59 +00:00
|
|
|
struct g_vfs_softc *sc;
|
2004-10-29 09:56:56 +00:00
|
|
|
struct bufobj *bo;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
g_topology_assert();
|
|
|
|
|
|
|
|
*cpp = NULL;
|
2010-04-03 08:53:53 +00:00
|
|
|
bo = &vp->v_bufobj;
|
|
|
|
if (bo->bo_private != vp)
|
|
|
|
return (EBUSY);
|
|
|
|
|
2004-10-29 09:56:56 +00:00
|
|
|
pp = g_dev_getprovider(vp->v_rdev);
|
|
|
|
if (pp == NULL)
|
|
|
|
return (ENOENT);
|
|
|
|
gp = g_new_geomf(&g_vfs_class, "%s.%s", fsname, pp->name);
|
2011-11-02 09:24:59 +00:00
|
|
|
sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
|
|
|
|
mtx_init(&sc->sc_mtx, "g_vfs", NULL, MTX_DEF);
|
|
|
|
sc->sc_bo = bo;
|
|
|
|
gp->softc = sc;
|
2004-10-29 09:56:56 +00:00
|
|
|
cp = g_new_consumer(gp);
|
2020-10-18 16:24:08 +00:00
|
|
|
error = g_attach(cp, pp);
|
|
|
|
if (error) {
|
|
|
|
g_wither_geom(gp, ENXIO);
|
|
|
|
return (error);
|
|
|
|
}
|
2011-07-10 00:41:31 +00:00
|
|
|
error = g_access(cp, 1, wr, wr);
|
2004-10-29 09:56:56 +00:00
|
|
|
if (error) {
|
|
|
|
g_wither_geom(gp, ENXIO);
|
|
|
|
return (error);
|
|
|
|
}
|
2005-01-24 22:41:21 +00:00
|
|
|
vnode_create_vobject(vp, pp->mediasize, curthread);
|
2004-10-29 09:56:56 +00:00
|
|
|
*cpp = cp;
|
2010-04-03 08:53:53 +00:00
|
|
|
cp->private = vp;
|
Merge GEOM direct dispatch changes from the projects/camlock branch.
When safety requirements are met, it allows to avoid passing I/O requests
to GEOM g_up/g_down thread, executing them directly in the caller context.
That allows to avoid CPU bottlenecks in g_up/g_down threads, plus avoid
several context switches per I/O.
The defined now safety requirements are:
- caller should not hold any locks and should be reenterable;
- callee should not depend on GEOM dual-threaded concurency semantics;
- on the way down, if request is unmapped while callee doesn't support it,
the context should be sleepable;
- kernel thread stack usage should be below 50%.
To keep compatibility with GEOM classes not meeting above requirements
new provider and consumer flags added:
- G_CF_DIRECT_SEND -- consumer code meets caller requirements (request);
- G_CF_DIRECT_RECEIVE -- consumer code meets callee requirements (done);
- G_PF_DIRECT_SEND -- provider code meets caller requirements (done);
- G_PF_DIRECT_RECEIVE -- provider code meets callee requirements (request).
Capable GEOM class can set them, allowing direct dispatch in cases where
it is safe. If any of requirements are not met, request is queued to
g_up or g_down thread same as before.
Such GEOM classes were reviewed and updated to support direct dispatch:
CONCAT, DEV, DISK, GATE, MD, MIRROR, MULTIPATH, NOP, PART, RAID, STRIPE,
VFS, ZERO, ZFS::VDEV, ZFS::ZVOL, all classes based on g_slice KPI (LABEL,
MAP, FLASHMAP, etc).
To declare direct completion capability disk(9) KPI got new flag equivalent
to G_PF_DIRECT_SEND -- DISKFLAG_DIRECT_COMPLETION. da(4) and ada(4) disk
drivers got it set now thanks to earlier CAM locking work.
This change more then twice increases peak block storage performance on
systems with manu CPUs, together with earlier CAM locking changes reaching
more then 1 million IOPS (512 byte raw reads from 16 SATA SSDs on 4 HBAs to
256 user-level threads).
Sponsored by: iXsystems, Inc.
MFC after: 2 months
2013-10-22 08:22:19 +00:00
|
|
|
cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
|
2004-10-29 09:56:56 +00:00
|
|
|
bo->bo_ops = g_vfs_bufops;
|
|
|
|
bo->bo_private = cp;
|
2010-04-02 15:12:31 +00:00
|
|
|
bo->bo_bsize = pp->sectorsize;
|
2004-10-29 09:56:56 +00:00
|
|
|
|
|
|
|
return (error);
|
|
|
|
}
|
2005-01-25 15:52:04 +00:00
|
|
|
|
|
|
|
void
|
2008-10-10 21:23:50 +00:00
|
|
|
g_vfs_close(struct g_consumer *cp)
|
2005-01-25 15:52:04 +00:00
|
|
|
{
|
|
|
|
struct g_geom *gp;
|
2011-11-02 09:24:59 +00:00
|
|
|
struct g_vfs_softc *sc;
|
2005-01-25 15:52:04 +00:00
|
|
|
|
|
|
|
g_topology_assert();
|
|
|
|
|
|
|
|
gp = cp->geom;
|
2011-11-02 09:24:59 +00:00
|
|
|
sc = gp->softc;
|
|
|
|
bufobj_invalbuf(sc->sc_bo, V_SAVE, 0, 0);
|
|
|
|
sc->sc_bo->bo_private = cp->private;
|
|
|
|
gp->softc = NULL;
|
|
|
|
mtx_destroy(&sc->sc_mtx);
|
|
|
|
if (!sc->sc_orphaned || cp->provider == NULL)
|
|
|
|
g_wither_geom_close(gp, ENXIO);
|
|
|
|
g_free(sc);
|
2005-01-25 15:52:04 +00:00
|
|
|
}
|