geom_vfs.c revision 223900
1137034Sphk/*-
2137034Sphk * Copyright (c) 2004 Poul-Henning Kamp
3137034Sphk * All rights reserved.
4137034Sphk *
5137034Sphk * Redistribution and use in source and binary forms, with or without
6137034Sphk * modification, are permitted provided that the following conditions
7137034Sphk * are met:
8137034Sphk * 1. Redistributions of source code must retain the above copyright
9137034Sphk *    notice, this list of conditions and the following disclaimer.
10137034Sphk * 2. Redistributions in binary form must reproduce the above copyright
11137034Sphk *    notice, this list of conditions and the following disclaimer in the
12137034Sphk *    documentation and/or other materials provided with the distribution.
13137034Sphk *
14137034Sphk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15137034Sphk * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16137034Sphk * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17137034Sphk * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18137034Sphk * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19137034Sphk * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20137034Sphk * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21137034Sphk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22137034Sphk * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23137034Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24137034Sphk * SUCH DAMAGE.
25137034Sphk */
26137034Sphk
27137034Sphk#include <sys/cdefs.h>
28137034Sphk__FBSDID("$FreeBSD: head/sys/geom/geom_vfs.c 223900 2011-07-10 00:41:31Z mckusick $");
29137034Sphk
30137034Sphk#include <sys/param.h>
31137034Sphk#include <sys/systm.h>
32137034Sphk#include <sys/bio.h>
33137034Sphk#include <sys/kernel.h>
34137034Sphk#include <sys/malloc.h>
35137034Sphk#include <sys/vnode.h>
36140940Sjeff#include <sys/mount.h>	/* XXX Temporary for VFS_LOCK_GIANT */
37137034Sphk
38137034Sphk#include <geom/geom.h>
39137034Sphk#include <geom/geom_vfs.h>
40137034Sphk
41137034Sphk/*
42137034Sphk * subroutines for use by filesystems.
43137034Sphk *
44137034Sphk * XXX: should maybe live somewhere else ?
45137034Sphk */
46137034Sphk#include <sys/buf.h>
47137034Sphk
48137034Sphkstatic struct buf_ops __g_vfs_bufops = {
49137034Sphk	.bop_name =	"GEOM_VFS",
50137034Sphk	.bop_write =	bufwrite,
51137034Sphk	.bop_strategy =	g_vfs_strategy,
52140056Sphk	.bop_sync =	bufsync,
53166193Skib	.bop_bdflush =	bufbdflush
54137034Sphk};
55137034Sphk
56137034Sphkstruct buf_ops *g_vfs_bufops = &__g_vfs_bufops;
57137034Sphk
58141624Sphkstatic g_orphan_t g_vfs_orphan;
59141624Sphk
60137034Sphkstatic struct g_class g_vfs_class = {
61137034Sphk	.name =		"VFS",
62137034Sphk	.version =	G_VERSION,
63137034Sphk	.orphan =	g_vfs_orphan,
64137034Sphk};
65137034Sphk
66137034SphkDECLARE_GEOM_CLASS(g_vfs_class, g_vfs);
67137034Sphk
68137034Sphkstatic void
69137034Sphkg_vfs_done(struct bio *bip)
70137034Sphk{
71137034Sphk	struct buf *bp;
72140940Sjeff	int vfslocked;
73137034Sphk
74187053Strasz	/*
75187053Strasz	 * Provider ('bio_to') could have withered away sometime
76187053Strasz	 * between incrementing the 'nend' in g_io_deliver() and now,
77187053Strasz	 * making 'bio_to' a dangling pointer.  We cannot do that
78187053Strasz	 * in g_wither_geom(), as it would require going over
79187053Strasz	 * the 'g_bio_run_up' list, resetting the pointer.
80187053Strasz	 */
81187053Strasz	if (bip->bio_from->provider == NULL)
82187053Strasz		bip->bio_to = NULL;
83187053Strasz
84137034Sphk	if (bip->bio_error) {
85137184Sphk		printf("g_vfs_done():");
86137034Sphk		g_print_bio(bip);
87137034Sphk		printf("error = %d\n", bip->bio_error);
88137034Sphk	}
89137034Sphk	bp = bip->bio_caller2;
90137034Sphk	bp->b_error = bip->bio_error;
91137034Sphk	bp->b_ioflags = bip->bio_flags;
92137034Sphk	if (bip->bio_error)
93137034Sphk		bp->b_ioflags |= BIO_ERROR;
94137034Sphk	bp->b_resid = bp->b_bcount - bip->bio_completed;
95137034Sphk	g_destroy_bio(bip);
96140940Sjeff	vfslocked = VFS_LOCK_GIANT(((struct mount *)NULL));
97137034Sphk	bufdone(bp);
98140940Sjeff	VFS_UNLOCK_GIANT(vfslocked);
99137034Sphk}
100137034Sphk
101137034Sphkvoid
102137034Sphkg_vfs_strategy(struct bufobj *bo, struct buf *bp)
103137034Sphk{
104137034Sphk	struct g_consumer *cp;
105137034Sphk	struct bio *bip;
106186188Strasz	int vfslocked;
107137034Sphk
108137034Sphk	cp = bo->bo_private;
109195257Strasz	/* G_VALID_CONSUMER(cp); We likely lack topology lock */
110137034Sphk
111186188Strasz	/*
112218909Sbrucec	 * If the provider has orphaned us, just return EXIO.
113186188Strasz	 */
114186188Strasz	if (cp->provider == NULL) {
115186188Strasz		bp->b_error = ENXIO;
116186188Strasz		bp->b_ioflags |= BIO_ERROR;
117186188Strasz		vfslocked = VFS_LOCK_GIANT(((struct mount *)NULL));
118186188Strasz		bufdone(bp);
119186188Strasz		VFS_UNLOCK_GIANT(vfslocked);
120186188Strasz		return;
121186188Strasz	}
122186188Strasz
123137034Sphk	bip = g_alloc_bio();
124137034Sphk	bip->bio_cmd = bp->b_iocmd;
125137034Sphk	bip->bio_offset = bp->b_iooffset;
126137034Sphk	bip->bio_data = bp->b_data;
127137034Sphk	bip->bio_done = g_vfs_done;
128137034Sphk	bip->bio_caller2 = bp;
129137034Sphk	bip->bio_length = bp->b_bcount;
130137034Sphk	g_io_request(bip, cp);
131137034Sphk}
132137034Sphk
133141624Sphkstatic void
134137034Sphkg_vfs_orphan(struct g_consumer *cp)
135137034Sphk{
136186188Strasz	struct g_geom *gp;
137137034Sphk
138186188Strasz	g_topology_assert();
139186188Strasz
140186188Strasz	gp = cp->geom;
141186188Strasz	g_trace(G_T_TOPOLOGY, "g_vfs_orphan(%p(%s))", cp, gp->name);
142186188Strasz	if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0)
143186188Strasz		g_access(cp, -cp->acr, -cp->acw, -cp->ace);
144186188Strasz	g_detach(cp);
145186188Strasz
146137034Sphk	/*
147187053Strasz	 * Do not destroy the geom.  Filesystem will do that during unmount.
148137034Sphk	 */
149137034Sphk}
150137034Sphk
151137034Sphkint
152137034Sphkg_vfs_open(struct vnode *vp, struct g_consumer **cpp, const char *fsname, int wr)
153137034Sphk{
154137034Sphk	struct g_geom *gp;
155137034Sphk	struct g_provider *pp;
156137034Sphk	struct g_consumer *cp;
157137034Sphk	struct bufobj *bo;
158156201Sjeff	int vfslocked;
159137034Sphk	int error;
160137034Sphk
161137034Sphk	g_topology_assert();
162137034Sphk
163137034Sphk	*cpp = NULL;
164206130Savg	bo = &vp->v_bufobj;
165206130Savg	if (bo->bo_private != vp)
166206130Savg		return (EBUSY);
167206130Savg
168137034Sphk	pp = g_dev_getprovider(vp->v_rdev);
169137034Sphk	if (pp == NULL)
170137034Sphk		return (ENOENT);
171137034Sphk	gp = g_new_geomf(&g_vfs_class, "%s.%s", fsname, pp->name);
172137034Sphk	cp = g_new_consumer(gp);
173137034Sphk	g_attach(cp, pp);
174223900Smckusick	error = g_access(cp, 1, wr, wr);
175137034Sphk	if (error) {
176137034Sphk		g_wither_geom(gp, ENXIO);
177137034Sphk		return (error);
178137034Sphk	}
179156201Sjeff	vfslocked = VFS_LOCK_GIANT(vp->v_mount);
180140773Sphk	vnode_create_vobject(vp, pp->mediasize, curthread);
181156201Sjeff	VFS_UNLOCK_GIANT(vfslocked);
182137034Sphk	*cpp = cp;
183206130Savg	cp->private = vp;
184137034Sphk	bo->bo_ops = g_vfs_bufops;
185137034Sphk	bo->bo_private = cp;
186206097Savg	bo->bo_bsize = pp->sectorsize;
187142079Sphk	gp->softc = bo;
188137034Sphk
189137034Sphk	return (error);
190137034Sphk}
191140822Sphk
192140822Sphkvoid
193183754Sattiliog_vfs_close(struct g_consumer *cp)
194140822Sphk{
195140822Sphk	struct g_geom *gp;
196142079Sphk	struct bufobj *bo;
197140822Sphk
198140822Sphk	g_topology_assert();
199140822Sphk
200140822Sphk	gp = cp->geom;
201142079Sphk	bo = gp->softc;
202183754Sattilio	bufobj_invalbuf(bo, V_SAVE, 0, 0);
203206130Savg	bo->bo_private = cp->private;
204140822Sphk	g_wither_geom_close(gp, ENXIO);
205140822Sphk}
206