]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/geom/cache/g_cache.c
Merge OpenSSL 1.1.1d.
[FreeBSD/FreeBSD.git] / sys / geom / cache / g_cache.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2006 Ruslan Ermilov <ru@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/module.h>
36 #include <sys/lock.h>
37 #include <sys/mutex.h>
38 #include <sys/bio.h>
39 #include <sys/sysctl.h>
40 #include <sys/malloc.h>
41 #include <sys/queue.h>
42 #include <sys/sbuf.h>
43 #include <sys/time.h>
44 #include <vm/uma.h>
45 #include <geom/geom.h>
46 #include <geom/geom_dbg.h>
47 #include <geom/cache/g_cache.h>
48
49 FEATURE(geom_cache, "GEOM cache module");
50
51 static MALLOC_DEFINE(M_GCACHE, "gcache_data", "GEOM_CACHE Data");
52
53 SYSCTL_DECL(_kern_geom);
54 static SYSCTL_NODE(_kern_geom, OID_AUTO, cache, CTLFLAG_RW, 0,
55     "GEOM_CACHE stuff");
56 static u_int g_cache_debug = 0;
57 SYSCTL_UINT(_kern_geom_cache, OID_AUTO, debug, CTLFLAG_RW, &g_cache_debug, 0,
58     "Debug level");
59 static u_int g_cache_enable = 1;
60 SYSCTL_UINT(_kern_geom_cache, OID_AUTO, enable, CTLFLAG_RW, &g_cache_enable, 0,
61     "");
62 static u_int g_cache_timeout = 10;
63 SYSCTL_UINT(_kern_geom_cache, OID_AUTO, timeout, CTLFLAG_RW, &g_cache_timeout,
64     0, "");
65 static u_int g_cache_idletime = 5;
66 SYSCTL_UINT(_kern_geom_cache, OID_AUTO, idletime, CTLFLAG_RW, &g_cache_idletime,
67     0, "");
68 static u_int g_cache_used_lo = 5;
69 static u_int g_cache_used_hi = 20;
70 static int
71 sysctl_handle_pct(SYSCTL_HANDLER_ARGS)
72 {
73         u_int val = *(u_int *)arg1;
74         int error;
75
76         error = sysctl_handle_int(oidp, &val, 0, req);
77         if (error || !req->newptr)
78                 return (error);
79         if (val > 100)
80                 return (EINVAL);
81         if ((arg1 == &g_cache_used_lo && val > g_cache_used_hi) ||
82             (arg1 == &g_cache_used_hi && g_cache_used_lo > val))
83                 return (EINVAL);
84         *(u_int *)arg1 = val;
85         return (0);
86 }
87 SYSCTL_PROC(_kern_geom_cache, OID_AUTO, used_lo, CTLTYPE_UINT|CTLFLAG_RW,
88         &g_cache_used_lo, 0, sysctl_handle_pct, "IU", "");
89 SYSCTL_PROC(_kern_geom_cache, OID_AUTO, used_hi, CTLTYPE_UINT|CTLFLAG_RW,
90         &g_cache_used_hi, 0, sysctl_handle_pct, "IU", "");
91
92
93 static int g_cache_destroy(struct g_cache_softc *sc, boolean_t force);
94 static g_ctl_destroy_geom_t g_cache_destroy_geom;
95
96 static g_taste_t g_cache_taste;
97 static g_ctl_req_t g_cache_config;
98 static g_dumpconf_t g_cache_dumpconf;
99
100 struct g_class g_cache_class = {
101         .name = G_CACHE_CLASS_NAME,
102         .version = G_VERSION,
103         .ctlreq = g_cache_config,
104         .taste = g_cache_taste,
105         .destroy_geom = g_cache_destroy_geom
106 };
107
108 #define OFF2BNO(off, sc)        ((off) >> (sc)->sc_bshift)
109 #define BNO2OFF(bno, sc)        ((bno) << (sc)->sc_bshift)
110
111
112 static struct g_cache_desc *
113 g_cache_alloc(struct g_cache_softc *sc)
114 {
115         struct g_cache_desc *dp;
116
117         mtx_assert(&sc->sc_mtx, MA_OWNED);
118
119         if (!TAILQ_EMPTY(&sc->sc_usedlist)) {
120                 dp = TAILQ_FIRST(&sc->sc_usedlist);
121                 TAILQ_REMOVE(&sc->sc_usedlist, dp, d_used);
122                 sc->sc_nused--;
123                 dp->d_flags = 0;
124                 LIST_REMOVE(dp, d_next);
125                 return (dp);
126         }
127         if (sc->sc_nent > sc->sc_maxent) {
128                 sc->sc_cachefull++;
129                 return (NULL);
130         }
131         dp = malloc(sizeof(*dp), M_GCACHE, M_NOWAIT | M_ZERO);
132         if (dp == NULL)
133                 return (NULL);
134         dp->d_data = uma_zalloc(sc->sc_zone, M_NOWAIT);
135         if (dp->d_data == NULL) {
136                 free(dp, M_GCACHE);
137                 return (NULL);
138         }
139         sc->sc_nent++;
140         return (dp);
141 }
142
143 static void
144 g_cache_free(struct g_cache_softc *sc, struct g_cache_desc *dp)
145 {
146
147         mtx_assert(&sc->sc_mtx, MA_OWNED);
148
149         uma_zfree(sc->sc_zone, dp->d_data);
150         free(dp, M_GCACHE);
151         sc->sc_nent--;
152 }
153
154 static void
155 g_cache_free_used(struct g_cache_softc *sc)
156 {
157         struct g_cache_desc *dp;
158         u_int n;
159
160         mtx_assert(&sc->sc_mtx, MA_OWNED);
161
162         n = g_cache_used_lo * sc->sc_maxent / 100;
163         while (sc->sc_nused > n) {
164                 KASSERT(!TAILQ_EMPTY(&sc->sc_usedlist), ("used list empty"));
165                 dp = TAILQ_FIRST(&sc->sc_usedlist);
166                 TAILQ_REMOVE(&sc->sc_usedlist, dp, d_used);
167                 sc->sc_nused--;
168                 LIST_REMOVE(dp, d_next);
169                 g_cache_free(sc, dp);
170         }
171 }
172
173 static void
174 g_cache_deliver(struct g_cache_softc *sc, struct bio *bp,
175     struct g_cache_desc *dp, int error)
176 {
177         off_t off1, off, len;
178
179         mtx_assert(&sc->sc_mtx, MA_OWNED);
180         KASSERT(OFF2BNO(bp->bio_offset, sc) <= dp->d_bno, ("wrong entry"));
181         KASSERT(OFF2BNO(bp->bio_offset + bp->bio_length - 1, sc) >=
182             dp->d_bno, ("wrong entry"));
183
184         off1 = BNO2OFF(dp->d_bno, sc);
185         off = MAX(bp->bio_offset, off1);
186         len = MIN(bp->bio_offset + bp->bio_length, off1 + sc->sc_bsize) - off;
187
188         if (bp->bio_error == 0)
189                 bp->bio_error = error;
190         if (bp->bio_error == 0) {
191                 bcopy(dp->d_data + (off - off1),
192                     bp->bio_data + (off - bp->bio_offset), len);
193         }
194         bp->bio_completed += len;
195         KASSERT(bp->bio_completed <= bp->bio_length, ("extra data"));
196         if (bp->bio_completed == bp->bio_length) {
197                 if (bp->bio_error != 0)
198                         bp->bio_completed = 0;
199                 g_io_deliver(bp, bp->bio_error);
200         }
201
202         if (dp->d_flags & D_FLAG_USED) {
203                 TAILQ_REMOVE(&sc->sc_usedlist, dp, d_used);
204                 TAILQ_INSERT_TAIL(&sc->sc_usedlist, dp, d_used);
205         } else if (OFF2BNO(off + len, sc) > dp->d_bno) {
206                 TAILQ_INSERT_TAIL(&sc->sc_usedlist, dp, d_used);
207                 sc->sc_nused++;
208                 dp->d_flags |= D_FLAG_USED;
209         }
210         dp->d_atime = time_uptime;
211 }
212
213 static void
214 g_cache_done(struct bio *bp)
215 {
216         struct g_cache_softc *sc;
217         struct g_cache_desc *dp;
218         struct bio *bp2, *tmpbp;
219
220         sc = bp->bio_from->geom->softc;
221         KASSERT(G_CACHE_DESC1(bp) == sc, ("corrupt bio_caller in g_cache_done()"));
222         dp = G_CACHE_DESC2(bp);
223         mtx_lock(&sc->sc_mtx);
224         bp2 = dp->d_biolist;
225         while (bp2 != NULL) {
226                 KASSERT(G_CACHE_NEXT_BIO1(bp2) == sc, ("corrupt bio_driver in g_cache_done()"));
227                 tmpbp = G_CACHE_NEXT_BIO2(bp2);
228                 g_cache_deliver(sc, bp2, dp, bp->bio_error);
229                 bp2 = tmpbp;
230         }
231         dp->d_biolist = NULL;
232         if (dp->d_flags & D_FLAG_INVALID) {
233                 sc->sc_invalid--;
234                 g_cache_free(sc, dp);
235         } else if (bp->bio_error) {
236                 LIST_REMOVE(dp, d_next);
237                 if (dp->d_flags & D_FLAG_USED) {
238                         TAILQ_REMOVE(&sc->sc_usedlist, dp, d_used);
239                         sc->sc_nused--;
240                 }
241                 g_cache_free(sc, dp);
242         }
243         mtx_unlock(&sc->sc_mtx);
244         g_destroy_bio(bp);
245 }
246
247 static struct g_cache_desc *
248 g_cache_lookup(struct g_cache_softc *sc, off_t bno)
249 {
250         struct g_cache_desc *dp;
251
252         mtx_assert(&sc->sc_mtx, MA_OWNED);
253
254         LIST_FOREACH(dp, &sc->sc_desclist[G_CACHE_BUCKET(bno)], d_next)
255                 if (dp->d_bno == bno)
256                         return (dp);
257         return (NULL);
258 }
259
260 static int
261 g_cache_read(struct g_cache_softc *sc, struct bio *bp)
262 {
263         struct bio *cbp;
264         struct g_cache_desc *dp;
265
266         mtx_lock(&sc->sc_mtx);
267         dp = g_cache_lookup(sc,
268             OFF2BNO(bp->bio_offset + bp->bio_completed, sc));
269         if (dp != NULL) {
270                 /* Add to waiters list or deliver. */
271                 sc->sc_cachehits++;
272                 if (dp->d_biolist != NULL) {
273                         G_CACHE_NEXT_BIO1(bp) = sc;
274                         G_CACHE_NEXT_BIO2(bp) = dp->d_biolist;
275                         dp->d_biolist = bp;
276                 } else
277                         g_cache_deliver(sc, bp, dp, 0);
278                 mtx_unlock(&sc->sc_mtx);
279                 return (0);
280         }
281
282         /* Cache miss.  Allocate entry and schedule bio.  */
283         sc->sc_cachemisses++;
284         dp = g_cache_alloc(sc);
285         if (dp == NULL) {
286                 mtx_unlock(&sc->sc_mtx);
287                 return (ENOMEM);
288         }
289         cbp = g_clone_bio(bp);
290         if (cbp == NULL) {
291                 g_cache_free(sc, dp);
292                 mtx_unlock(&sc->sc_mtx);
293                 return (ENOMEM);
294         }
295
296         dp->d_bno = OFF2BNO(bp->bio_offset + bp->bio_completed, sc);
297         G_CACHE_NEXT_BIO1(bp) = sc;
298         G_CACHE_NEXT_BIO2(bp) = NULL;
299         dp->d_biolist = bp;
300         LIST_INSERT_HEAD(&sc->sc_desclist[G_CACHE_BUCKET(dp->d_bno)],
301             dp, d_next);
302         mtx_unlock(&sc->sc_mtx);
303
304         G_CACHE_DESC1(cbp) = sc;
305         G_CACHE_DESC2(cbp) = dp;
306         cbp->bio_done = g_cache_done;
307         cbp->bio_offset = BNO2OFF(dp->d_bno, sc);
308         cbp->bio_data = dp->d_data;
309         cbp->bio_length = sc->sc_bsize;
310         g_io_request(cbp, LIST_FIRST(&bp->bio_to->geom->consumer));
311         return (0);
312 }
313
314 static void
315 g_cache_invalidate(struct g_cache_softc *sc, struct bio *bp)
316 {
317         struct g_cache_desc *dp;
318         off_t bno, lim;
319
320         mtx_lock(&sc->sc_mtx);
321         bno = OFF2BNO(bp->bio_offset, sc);
322         lim = OFF2BNO(bp->bio_offset + bp->bio_length - 1, sc);
323         do {
324                 if ((dp = g_cache_lookup(sc, bno)) != NULL) {
325                         LIST_REMOVE(dp, d_next);
326                         if (dp->d_flags & D_FLAG_USED) {
327                                 TAILQ_REMOVE(&sc->sc_usedlist, dp, d_used);
328                                 sc->sc_nused--;
329                         }
330                         if (dp->d_biolist == NULL)
331                                 g_cache_free(sc, dp);
332                         else {
333                                 dp->d_flags = D_FLAG_INVALID;
334                                 sc->sc_invalid++;
335                         }
336                 }
337                 bno++;
338         } while (bno <= lim);
339         mtx_unlock(&sc->sc_mtx);
340 }
341
342 static void
343 g_cache_start(struct bio *bp)
344 {
345         struct g_cache_softc *sc;
346         struct g_geom *gp;
347         struct g_cache_desc *dp;
348         struct bio *cbp;
349
350         gp = bp->bio_to->geom;
351         sc = gp->softc;
352         G_CACHE_LOGREQ(bp, "Request received.");
353         switch (bp->bio_cmd) {
354         case BIO_READ:
355                 sc->sc_reads++;
356                 sc->sc_readbytes += bp->bio_length;
357                 if (!g_cache_enable)
358                         break;
359                 if (bp->bio_offset + bp->bio_length > sc->sc_tail)
360                         break;
361                 if (OFF2BNO(bp->bio_offset, sc) ==
362                     OFF2BNO(bp->bio_offset + bp->bio_length - 1, sc)) {
363                         sc->sc_cachereads++;
364                         sc->sc_cachereadbytes += bp->bio_length;
365                         if (g_cache_read(sc, bp) == 0)
366                                 return;
367                         sc->sc_cachereads--;
368                         sc->sc_cachereadbytes -= bp->bio_length;
369                         break;
370                 } else if (OFF2BNO(bp->bio_offset, sc) + 1 ==
371                     OFF2BNO(bp->bio_offset + bp->bio_length - 1, sc)) {
372                         mtx_lock(&sc->sc_mtx);
373                         dp = g_cache_lookup(sc, OFF2BNO(bp->bio_offset, sc));
374                         if (dp == NULL || dp->d_biolist != NULL) {
375                                 mtx_unlock(&sc->sc_mtx);
376                                 break;
377                         }
378                         sc->sc_cachereads++;
379                         sc->sc_cachereadbytes += bp->bio_length;
380                         g_cache_deliver(sc, bp, dp, 0);
381                         mtx_unlock(&sc->sc_mtx);
382                         if (g_cache_read(sc, bp) == 0)
383                                 return;
384                         sc->sc_cachereads--;
385                         sc->sc_cachereadbytes -= bp->bio_length;
386                         break;
387                 }
388                 break;
389         case BIO_WRITE:
390                 sc->sc_writes++;
391                 sc->sc_wrotebytes += bp->bio_length;
392                 g_cache_invalidate(sc, bp);
393                 break;
394         }
395         cbp = g_clone_bio(bp);
396         if (cbp == NULL) {
397                 g_io_deliver(bp, ENOMEM);
398                 return;
399         }
400         cbp->bio_done = g_std_done;
401         G_CACHE_LOGREQ(cbp, "Sending request.");
402         g_io_request(cbp, LIST_FIRST(&gp->consumer));
403 }
404
405 static void
406 g_cache_go(void *arg)
407 {
408         struct g_cache_softc *sc = arg;
409         struct g_cache_desc *dp;
410         int i;
411
412         mtx_assert(&sc->sc_mtx, MA_OWNED);
413
414         /* Forcibly mark idle ready entries as used. */
415         for (i = 0; i < G_CACHE_BUCKETS; i++) {
416                 LIST_FOREACH(dp, &sc->sc_desclist[i], d_next) {
417                         if (dp->d_flags & D_FLAG_USED ||
418                             dp->d_biolist != NULL ||
419                             time_uptime - dp->d_atime < g_cache_idletime)
420                                 continue;
421                         TAILQ_INSERT_TAIL(&sc->sc_usedlist, dp, d_used);
422                         sc->sc_nused++;
423                         dp->d_flags |= D_FLAG_USED;
424                 }
425         }
426
427         /* Keep the number of used entries low. */
428         if (sc->sc_nused > g_cache_used_hi * sc->sc_maxent / 100)
429                 g_cache_free_used(sc);
430
431         callout_reset(&sc->sc_callout, g_cache_timeout * hz, g_cache_go, sc);
432 }
433
434 static int
435 g_cache_access(struct g_provider *pp, int dr, int dw, int de)
436 {
437         struct g_geom *gp;
438         struct g_consumer *cp;
439         int error;
440
441         gp = pp->geom;
442         cp = LIST_FIRST(&gp->consumer);
443         error = g_access(cp, dr, dw, de);
444
445         return (error);
446 }
447
448 static void
449 g_cache_orphan(struct g_consumer *cp)
450 {
451
452         g_topology_assert();
453         g_cache_destroy(cp->geom->softc, 1);
454 }
455
456 static struct g_cache_softc *
457 g_cache_find_device(struct g_class *mp, const char *name)
458 {
459         struct g_geom *gp;
460
461         LIST_FOREACH(gp, &mp->geom, geom) {
462                 if (strcmp(gp->name, name) == 0)
463                         return (gp->softc);
464         }
465         return (NULL);
466 }
467
468 static struct g_geom *
469 g_cache_create(struct g_class *mp, struct g_provider *pp,
470     const struct g_cache_metadata *md, u_int type)
471 {
472         struct g_cache_softc *sc;
473         struct g_geom *gp;
474         struct g_provider *newpp;
475         struct g_consumer *cp;
476         u_int bshift;
477         int i;
478
479         g_topology_assert();
480
481         gp = NULL;
482         newpp = NULL;
483         cp = NULL;
484
485         G_CACHE_DEBUG(1, "Creating device %s.", md->md_name);
486
487         /* Cache size is minimum 100. */
488         if (md->md_size < 100) {
489                 G_CACHE_DEBUG(0, "Invalid size for device %s.", md->md_name);
490                 return (NULL);
491         }
492
493         /* Block size restrictions. */
494         bshift = ffs(md->md_bsize) - 1;
495         if (md->md_bsize == 0 || md->md_bsize > MAXPHYS ||
496             md->md_bsize != 1 << bshift ||
497             (md->md_bsize % pp->sectorsize) != 0) {
498                 G_CACHE_DEBUG(0, "Invalid blocksize for provider %s.", pp->name);
499                 return (NULL);
500         }
501
502         /* Check for duplicate unit. */
503         if (g_cache_find_device(mp, (const char *)&md->md_name) != NULL) {
504                 G_CACHE_DEBUG(0, "Provider %s already exists.", md->md_name);
505                 return (NULL);
506         }
507
508         gp = g_new_geomf(mp, "%s", md->md_name);
509         sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
510         sc->sc_type = type;
511         sc->sc_bshift = bshift;
512         sc->sc_bsize = 1 << bshift;
513         sc->sc_zone = uma_zcreate("gcache", sc->sc_bsize, NULL, NULL, NULL, NULL,
514             UMA_ALIGN_PTR, 0);
515         mtx_init(&sc->sc_mtx, "GEOM CACHE mutex", NULL, MTX_DEF);
516         for (i = 0; i < G_CACHE_BUCKETS; i++)
517                 LIST_INIT(&sc->sc_desclist[i]);
518         TAILQ_INIT(&sc->sc_usedlist);
519         sc->sc_maxent = md->md_size;
520         callout_init_mtx(&sc->sc_callout, &sc->sc_mtx, 0);
521         gp->softc = sc;
522         sc->sc_geom = gp;
523         gp->start = g_cache_start;
524         gp->orphan = g_cache_orphan;
525         gp->access = g_cache_access;
526         gp->dumpconf = g_cache_dumpconf;
527
528         newpp = g_new_providerf(gp, "cache/%s", gp->name);
529         newpp->sectorsize = pp->sectorsize;
530         newpp->mediasize = pp->mediasize;
531         if (type == G_CACHE_TYPE_AUTOMATIC)
532                 newpp->mediasize -= pp->sectorsize;
533         sc->sc_tail = BNO2OFF(OFF2BNO(newpp->mediasize, sc), sc);
534
535         cp = g_new_consumer(gp);
536         if (g_attach(cp, pp) != 0) {
537                 G_CACHE_DEBUG(0, "Cannot attach to provider %s.", pp->name);
538                 g_destroy_consumer(cp);
539                 g_destroy_provider(newpp);
540                 mtx_destroy(&sc->sc_mtx);
541                 g_free(sc);
542                 g_destroy_geom(gp);
543                 return (NULL);
544         }
545
546         g_error_provider(newpp, 0);
547         G_CACHE_DEBUG(0, "Device %s created.", gp->name);
548         callout_reset(&sc->sc_callout, g_cache_timeout * hz, g_cache_go, sc);
549         return (gp);
550 }
551
552 static int
553 g_cache_destroy(struct g_cache_softc *sc, boolean_t force)
554 {
555         struct g_geom *gp;
556         struct g_provider *pp;
557         struct g_cache_desc *dp, *dp2;
558         int i;
559
560         g_topology_assert();
561         if (sc == NULL)
562                 return (ENXIO);
563         gp = sc->sc_geom;
564         pp = LIST_FIRST(&gp->provider);
565         if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) {
566                 if (force) {
567                         G_CACHE_DEBUG(0, "Device %s is still open, so it "
568                             "can't be definitely removed.", pp->name);
569                 } else {
570                         G_CACHE_DEBUG(1, "Device %s is still open (r%dw%de%d).",
571                             pp->name, pp->acr, pp->acw, pp->ace);
572                         return (EBUSY);
573                 }
574         } else {
575                 G_CACHE_DEBUG(0, "Device %s removed.", gp->name);
576         }
577         callout_drain(&sc->sc_callout);
578         mtx_lock(&sc->sc_mtx);
579         for (i = 0; i < G_CACHE_BUCKETS; i++) {
580                 dp = LIST_FIRST(&sc->sc_desclist[i]);
581                 while (dp != NULL) {
582                         dp2 = LIST_NEXT(dp, d_next);
583                         g_cache_free(sc, dp);
584                         dp = dp2;
585                 }
586         }
587         mtx_unlock(&sc->sc_mtx);
588         mtx_destroy(&sc->sc_mtx);
589         uma_zdestroy(sc->sc_zone);
590         g_free(sc);
591         gp->softc = NULL;
592         g_wither_geom(gp, ENXIO);
593
594         return (0);
595 }
596
597 static int
598 g_cache_destroy_geom(struct gctl_req *req, struct g_class *mp, struct g_geom *gp)
599 {
600
601         return (g_cache_destroy(gp->softc, 0));
602 }
603
604 static int
605 g_cache_read_metadata(struct g_consumer *cp, struct g_cache_metadata *md)
606 {
607         struct g_provider *pp;
608         u_char *buf;
609         int error;
610
611         g_topology_assert();
612
613         error = g_access(cp, 1, 0, 0);
614         if (error != 0)
615                 return (error);
616         pp = cp->provider;
617         g_topology_unlock();
618         buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize,
619             &error);
620         g_topology_lock();
621         g_access(cp, -1, 0, 0);
622         if (buf == NULL)
623                 return (error);
624
625         /* Decode metadata. */
626         cache_metadata_decode(buf, md);
627         g_free(buf);
628
629         return (0);
630 }
631
632 static int
633 g_cache_write_metadata(struct g_consumer *cp, struct g_cache_metadata *md)
634 {
635         struct g_provider *pp;
636         u_char *buf;
637         int error;
638
639         g_topology_assert();
640
641         error = g_access(cp, 0, 1, 0);
642         if (error != 0)
643                 return (error);
644         pp = cp->provider;
645         buf = malloc((size_t)pp->sectorsize, M_GCACHE, M_WAITOK | M_ZERO);
646         cache_metadata_encode(md, buf);
647         g_topology_unlock();
648         error = g_write_data(cp, pp->mediasize - pp->sectorsize, buf, pp->sectorsize);
649         g_topology_lock();
650         g_access(cp, 0, -1, 0);
651         free(buf, M_GCACHE);
652
653         return (error);
654 }
655
656 static struct g_geom *
657 g_cache_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
658 {
659         struct g_cache_metadata md;
660         struct g_consumer *cp;
661         struct g_geom *gp;
662         int error;
663
664         g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name);
665         g_topology_assert();
666
667         G_CACHE_DEBUG(3, "Tasting %s.", pp->name);
668
669         gp = g_new_geomf(mp, "cache:taste");
670         gp->start = g_cache_start;
671         gp->orphan = g_cache_orphan;
672         gp->access = g_cache_access;
673         cp = g_new_consumer(gp);
674         g_attach(cp, pp);
675         error = g_cache_read_metadata(cp, &md);
676         g_detach(cp);
677         g_destroy_consumer(cp);
678         g_destroy_geom(gp);
679         if (error != 0)
680                 return (NULL);
681
682         if (strcmp(md.md_magic, G_CACHE_MAGIC) != 0)
683                 return (NULL);
684         if (md.md_version > G_CACHE_VERSION) {
685                 printf("geom_cache.ko module is too old to handle %s.\n",
686                     pp->name);
687                 return (NULL);
688         }
689         if (md.md_provsize != pp->mediasize)
690                 return (NULL);
691
692         gp = g_cache_create(mp, pp, &md, G_CACHE_TYPE_AUTOMATIC);
693         if (gp == NULL) {
694                 G_CACHE_DEBUG(0, "Can't create %s.", md.md_name);
695                 return (NULL);
696         }
697         return (gp);
698 }
699
700 static void
701 g_cache_ctl_create(struct gctl_req *req, struct g_class *mp)
702 {
703         struct g_cache_metadata md;
704         struct g_provider *pp;
705         struct g_geom *gp;
706         intmax_t *bsize, *size;
707         const char *name;
708         int *nargs;
709
710         g_topology_assert();
711
712         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
713         if (nargs == NULL) {
714                 gctl_error(req, "No '%s' argument", "nargs");
715                 return;
716         }
717         if (*nargs != 2) {
718                 gctl_error(req, "Invalid number of arguments.");
719                 return;
720         }
721
722         strlcpy(md.md_magic, G_CACHE_MAGIC, sizeof(md.md_magic));
723         md.md_version = G_CACHE_VERSION;
724         name = gctl_get_asciiparam(req, "arg0");
725         if (name == NULL) {
726                 gctl_error(req, "No 'arg0' argument");
727                 return;
728         }
729         strlcpy(md.md_name, name, sizeof(md.md_name));
730
731         size = gctl_get_paraml(req, "size", sizeof(*size));
732         if (size == NULL) {
733                 gctl_error(req, "No '%s' argument", "size");
734                 return;
735         }
736         if ((u_int)*size < 100) {
737                 gctl_error(req, "Invalid '%s' argument", "size");
738                 return;
739         }
740         md.md_size = (u_int)*size;
741
742         bsize = gctl_get_paraml(req, "blocksize", sizeof(*bsize));
743         if (bsize == NULL) {
744                 gctl_error(req, "No '%s' argument", "blocksize");
745                 return;
746         }
747         if (*bsize < 0) {
748                 gctl_error(req, "Invalid '%s' argument", "blocksize");
749                 return;
750         }
751         md.md_bsize = (u_int)*bsize;
752
753         /* This field is not important here. */
754         md.md_provsize = 0;
755
756         name = gctl_get_asciiparam(req, "arg1");
757         if (name == NULL) {
758                 gctl_error(req, "No 'arg1' argument");
759                 return;
760         }
761         if (strncmp(name, "/dev/", strlen("/dev/")) == 0)
762                 name += strlen("/dev/");
763         pp = g_provider_by_name(name);
764         if (pp == NULL) {
765                 G_CACHE_DEBUG(1, "Provider %s is invalid.", name);
766                 gctl_error(req, "Provider %s is invalid.", name);
767                 return;
768         }
769         gp = g_cache_create(mp, pp, &md, G_CACHE_TYPE_MANUAL);
770         if (gp == NULL) {
771                 gctl_error(req, "Can't create %s.", md.md_name);
772                 return;
773         }
774 }
775
776 static void
777 g_cache_ctl_configure(struct gctl_req *req, struct g_class *mp)
778 {
779         struct g_cache_metadata md;
780         struct g_cache_softc *sc;
781         struct g_consumer *cp;
782         intmax_t *bsize, *size;
783         const char *name;
784         int error, *nargs;
785
786         g_topology_assert();
787
788         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
789         if (nargs == NULL) {
790                 gctl_error(req, "No '%s' argument", "nargs");
791                 return;
792         }
793         if (*nargs != 1) {
794                 gctl_error(req, "Missing device.");
795                 return;
796         }
797
798         name = gctl_get_asciiparam(req, "arg0");
799         if (name == NULL) {
800                 gctl_error(req, "No 'arg0' argument");
801                 return;
802         }
803         sc = g_cache_find_device(mp, name);
804         if (sc == NULL) {
805                 G_CACHE_DEBUG(1, "Device %s is invalid.", name);
806                 gctl_error(req, "Device %s is invalid.", name);
807                 return;
808         }
809
810         size = gctl_get_paraml(req, "size", sizeof(*size));
811         if (size == NULL) {
812                 gctl_error(req, "No '%s' argument", "size");
813                 return;
814         }
815         if ((u_int)*size != 0 && (u_int)*size < 100) {
816                 gctl_error(req, "Invalid '%s' argument", "size");
817                 return;
818         }
819         if ((u_int)*size != 0)
820                 sc->sc_maxent = (u_int)*size;
821
822         bsize = gctl_get_paraml(req, "blocksize", sizeof(*bsize));
823         if (bsize == NULL) {
824                 gctl_error(req, "No '%s' argument", "blocksize");
825                 return;
826         }
827         if (*bsize < 0) {
828                 gctl_error(req, "Invalid '%s' argument", "blocksize");
829                 return;
830         }
831
832         if (sc->sc_type != G_CACHE_TYPE_AUTOMATIC)
833                 return;
834
835         strlcpy(md.md_name, name, sizeof(md.md_name));
836         strlcpy(md.md_magic, G_CACHE_MAGIC, sizeof(md.md_magic));
837         md.md_version = G_CACHE_VERSION;
838         if ((u_int)*size != 0)
839                 md.md_size = (u_int)*size;
840         else
841                 md.md_size = sc->sc_maxent;
842         if ((u_int)*bsize != 0)
843                 md.md_bsize = (u_int)*bsize;
844         else
845                 md.md_bsize = sc->sc_bsize;
846         cp = LIST_FIRST(&sc->sc_geom->consumer);
847         md.md_provsize = cp->provider->mediasize;
848         error = g_cache_write_metadata(cp, &md);
849         if (error == 0)
850                 G_CACHE_DEBUG(2, "Metadata on %s updated.", cp->provider->name);
851         else
852                 G_CACHE_DEBUG(0, "Cannot update metadata on %s (error=%d).",
853                     cp->provider->name, error);
854 }
855
856 static void
857 g_cache_ctl_destroy(struct gctl_req *req, struct g_class *mp)
858 {
859         int *nargs, *force, error, i;
860         struct g_cache_softc *sc;
861         const char *name;
862         char param[16];
863
864         g_topology_assert();
865
866         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
867         if (nargs == NULL) {
868                 gctl_error(req, "No '%s' argument", "nargs");
869                 return;
870         }
871         if (*nargs <= 0) {
872                 gctl_error(req, "Missing device(s).");
873                 return;
874         }
875         force = gctl_get_paraml(req, "force", sizeof(*force));
876         if (force == NULL) {
877                 gctl_error(req, "No 'force' argument");
878                 return;
879         }
880
881         for (i = 0; i < *nargs; i++) {
882                 snprintf(param, sizeof(param), "arg%d", i);
883                 name = gctl_get_asciiparam(req, param);
884                 if (name == NULL) {
885                         gctl_error(req, "No 'arg%d' argument", i);
886                         return;
887                 }
888                 sc = g_cache_find_device(mp, name);
889                 if (sc == NULL) {
890                         G_CACHE_DEBUG(1, "Device %s is invalid.", name);
891                         gctl_error(req, "Device %s is invalid.", name);
892                         return;
893                 }
894                 error = g_cache_destroy(sc, *force);
895                 if (error != 0) {
896                         gctl_error(req, "Cannot destroy device %s (error=%d).",
897                             sc->sc_name, error);
898                         return;
899                 }
900         }
901 }
902
903 static void
904 g_cache_ctl_reset(struct gctl_req *req, struct g_class *mp)
905 {
906         struct g_cache_softc *sc;
907         const char *name;
908         char param[16];
909         int i, *nargs;
910
911         g_topology_assert();
912
913         nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
914         if (nargs == NULL) {
915                 gctl_error(req, "No '%s' argument", "nargs");
916                 return;
917         }
918         if (*nargs <= 0) {
919                 gctl_error(req, "Missing device(s).");
920                 return;
921         }
922
923         for (i = 0; i < *nargs; i++) {
924                 snprintf(param, sizeof(param), "arg%d", i);
925                 name = gctl_get_asciiparam(req, param);
926                 if (name == NULL) {
927                         gctl_error(req, "No 'arg%d' argument", i);
928                         return;
929                 }
930                 sc = g_cache_find_device(mp, name);
931                 if (sc == NULL) {
932                         G_CACHE_DEBUG(1, "Device %s is invalid.", name);
933                         gctl_error(req, "Device %s is invalid.", name);
934                         return;
935                 }
936                 sc->sc_reads = 0;
937                 sc->sc_readbytes = 0;
938                 sc->sc_cachereads = 0;
939                 sc->sc_cachereadbytes = 0;
940                 sc->sc_cachehits = 0;
941                 sc->sc_cachemisses = 0;
942                 sc->sc_cachefull = 0;
943                 sc->sc_writes = 0;
944                 sc->sc_wrotebytes = 0;
945         }
946 }
947
948 static void
949 g_cache_config(struct gctl_req *req, struct g_class *mp, const char *verb)
950 {
951         uint32_t *version;
952
953         g_topology_assert();
954
955         version = gctl_get_paraml(req, "version", sizeof(*version));
956         if (version == NULL) {
957                 gctl_error(req, "No '%s' argument.", "version");
958                 return;
959         }
960         if (*version != G_CACHE_VERSION) {
961                 gctl_error(req, "Userland and kernel parts are out of sync.");
962                 return;
963         }
964
965         if (strcmp(verb, "create") == 0) {
966                 g_cache_ctl_create(req, mp);
967                 return;
968         } else if (strcmp(verb, "configure") == 0) {
969                 g_cache_ctl_configure(req, mp);
970                 return;
971         } else if (strcmp(verb, "destroy") == 0 ||
972             strcmp(verb, "stop") == 0) {
973                 g_cache_ctl_destroy(req, mp);
974                 return;
975         } else if (strcmp(verb, "reset") == 0) {
976                 g_cache_ctl_reset(req, mp);
977                 return;
978         }
979
980         gctl_error(req, "Unknown verb.");
981 }
982
983 static void
984 g_cache_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
985     struct g_consumer *cp, struct g_provider *pp)
986 {
987         struct g_cache_softc *sc;
988
989         if (pp != NULL || cp != NULL)
990                 return;
991         sc = gp->softc;
992         sbuf_printf(sb, "%s<Size>%u</Size>\n", indent, sc->sc_maxent);
993         sbuf_printf(sb, "%s<BlockSize>%u</BlockSize>\n", indent, sc->sc_bsize);
994         sbuf_printf(sb, "%s<TailOffset>%ju</TailOffset>\n", indent,
995             (uintmax_t)sc->sc_tail);
996         sbuf_printf(sb, "%s<Entries>%u</Entries>\n", indent, sc->sc_nent);
997         sbuf_printf(sb, "%s<UsedEntries>%u</UsedEntries>\n", indent,
998             sc->sc_nused);
999         sbuf_printf(sb, "%s<InvalidEntries>%u</InvalidEntries>\n", indent,
1000             sc->sc_invalid);
1001         sbuf_printf(sb, "%s<Reads>%ju</Reads>\n", indent, sc->sc_reads);
1002         sbuf_printf(sb, "%s<ReadBytes>%ju</ReadBytes>\n", indent,
1003             sc->sc_readbytes);
1004         sbuf_printf(sb, "%s<CacheReads>%ju</CacheReads>\n", indent,
1005             sc->sc_cachereads);
1006         sbuf_printf(sb, "%s<CacheReadBytes>%ju</CacheReadBytes>\n", indent,
1007             sc->sc_cachereadbytes);
1008         sbuf_printf(sb, "%s<CacheHits>%ju</CacheHits>\n", indent,
1009             sc->sc_cachehits);
1010         sbuf_printf(sb, "%s<CacheMisses>%ju</CacheMisses>\n", indent,
1011             sc->sc_cachemisses);
1012         sbuf_printf(sb, "%s<CacheFull>%ju</CacheFull>\n", indent,
1013             sc->sc_cachefull);
1014         sbuf_printf(sb, "%s<Writes>%ju</Writes>\n", indent, sc->sc_writes);
1015         sbuf_printf(sb, "%s<WroteBytes>%ju</WroteBytes>\n", indent,
1016             sc->sc_wrotebytes);
1017 }
1018
1019 DECLARE_GEOM_CLASS(g_cache_class, g_cache);
1020 MODULE_VERSION(geom_cache, 0);