The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/fss.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: fss.c,v 1.7 2004/02/24 15:12:51 wiz Exp $      */
    2 
    3 /*-
    4  * Copyright (c) 2003 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Juergen Hannken-Illjes.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by the NetBSD
   21  *      Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /*
   40  * File system snapshot disk driver.
   41  *
   42  * Block/character interface to the snapshot of a mounted file system.
   43  */
   44 
   45 #include <sys/cdefs.h>
   46 __KERNEL_RCSID(0, "$NetBSD: fss.c,v 1.7 2004/02/24 15:12:51 wiz Exp $");
   47 
   48 #include "fss.h"
   49 
   50 #include <sys/param.h>
   51 #include <sys/systm.h>
   52 #include <sys/namei.h>
   53 #include <sys/proc.h>
   54 #include <sys/errno.h>
   55 #include <sys/buf.h>
   56 #include <sys/malloc.h>
   57 #include <sys/ioctl.h>
   58 #include <sys/disklabel.h>
   59 #include <sys/device.h>
   60 #include <sys/disk.h>
   61 #include <sys/stat.h>
   62 #include <sys/mount.h>
   63 #include <sys/vnode.h>
   64 #include <sys/file.h>
   65 #include <sys/uio.h>
   66 #include <sys/conf.h>
   67 #include <sys/kthread.h>
   68 
   69 #include <miscfs/specfs/specdev.h>
   70 
   71 #include <dev/fssvar.h>
   72 
   73 #include <machine/stdarg.h>
   74 
   75 #ifdef DEBUG
   76 #define FSS_STATISTICS
   77 #endif
   78 
   79 #ifdef FSS_STATISTICS
   80 struct fss_stat {
   81         u_int64_t       cow_calls;
   82         u_int64_t       cow_copied;
   83         u_int64_t       cow_cache_full;
   84         u_int64_t       indir_read;
   85         u_int64_t       indir_write;
   86 };
   87 
   88 static struct fss_stat fss_stat[NFSS];
   89 
   90 #define FSS_STAT_INC(sc, field) \
   91                         do { \
   92                                 fss_stat[sc->sc_unit].field++; \
   93                         } while (0)
   94 #define FSS_STAT_SET(sc, field, value) \
   95                         do { \
   96                                 fss_stat[sc->sc_unit].field = value; \
   97                         } while (0)
   98 #define FSS_STAT_ADD(sc, field, value) \
   99                         do { \
  100                                 fss_stat[sc->sc_unit].field += value; \
  101                         } while (0)
  102 #define FSS_STAT_VAL(sc, field) fss_stat[sc->sc_unit].field
  103 #define FSS_STAT_CLEAR(sc) \
  104                         do { \
  105                                 memset(&fss_stat[sc->sc_unit], 0, \
  106                                     sizeof(struct fss_stat)); \
  107                         } while (0)
  108 #else /* FSS_STATISTICS */
  109 #define FSS_STAT_INC(sc, field)
  110 #define FSS_STAT_SET(sc, field, value)
  111 #define FSS_STAT_ADD(sc, field, value)
  112 #define FSS_STAT_CLEAR(sc)
  113 #endif /* FSS_STATISTICS */
  114 
  115 static struct fss_softc fss_softc[NFSS];
  116 
  117 void fssattach(int);
  118 
  119 dev_type_open(fss_open);
  120 dev_type_close(fss_close);
  121 dev_type_read(fss_read);
  122 dev_type_write(fss_write);
  123 dev_type_ioctl(fss_ioctl);
  124 dev_type_strategy(fss_strategy);
  125 dev_type_dump(fss_dump);
  126 dev_type_size(fss_size);
  127 
  128 static void fss_copy_on_write(void *, struct buf *);
  129 static inline void fss_error(struct fss_softc *, const char *, ...);
  130 static int fss_create_files(struct fss_softc *, struct fss_set *,
  131     off_t *, struct proc *);
  132 static int fss_create_snapshot(struct fss_softc *, struct fss_set *,
  133     struct proc *);
  134 static int fss_delete_snapshot(struct fss_softc *, struct proc *);
  135 static int fss_softc_alloc(struct fss_softc *);
  136 static void fss_softc_free(struct fss_softc *);
  137 static void fss_cluster_iodone(struct buf *);
  138 static void fss_read_cluster(struct fss_softc *, u_int32_t);
  139 static int fss_write_cluster(struct fss_cache *, u_int32_t);
  140 static void fss_bs_thread(void *);
  141 static int fss_bmap(struct fss_softc *, off_t, int,
  142     struct vnode **, daddr_t *, int *);
  143 static int fss_bs_io(struct fss_softc *, fss_io_type,
  144     u_int32_t, long, int, caddr_t);
  145 static u_int32_t *fss_bs_indir(struct fss_softc *, u_int32_t);
  146 
  147 const struct bdevsw fss_bdevsw = {
  148         fss_open, fss_close, fss_strategy, fss_ioctl,
  149         fss_dump, fss_size, D_DISK
  150 };
  151 
  152 const struct cdevsw fss_cdevsw = {
  153         fss_open, fss_close, fss_read, fss_write, fss_ioctl,
  154         nostop, notty, nopoll, nommap, nokqfilter, D_DISK
  155 };
  156 
  157 void
  158 fssattach(int num)
  159 {
  160         int i;
  161         struct fss_softc *sc;
  162 
  163         for (i = 0; i < NFSS; i++) {
  164                 sc = &fss_softc[i];
  165                 sc->sc_unit = i;
  166                 sc->sc_bdev = NODEV;
  167                 simple_lock_init(&sc->sc_slock);
  168                 bufq_alloc(&sc->sc_bufq, BUFQ_FCFS|BUFQ_SORT_RAWBLOCK);
  169         }
  170 }
  171 
  172 int
  173 fss_open(dev_t dev, int flags, int mode, struct proc *p)
  174 {
  175         struct fss_softc *sc;
  176 
  177         if ((sc = FSS_DEV_TO_SOFTC(dev)) == NULL)
  178                 return ENODEV;
  179 
  180         return 0;
  181 }
  182 
  183 int
  184 fss_close(dev_t dev, int flags, int mode, struct proc *p)
  185 {
  186         struct fss_softc *sc;
  187 
  188         if ((sc = FSS_DEV_TO_SOFTC(dev)) == NULL)
  189                 return ENODEV;
  190 
  191         return 0;
  192 }
  193 
  194 void
  195 fss_strategy(struct buf *bp)
  196 {
  197         int s;
  198         struct fss_softc *sc;
  199 
  200         sc = FSS_DEV_TO_SOFTC(bp->b_dev);
  201 
  202         FSS_LOCK(sc, s);
  203 
  204         if ((bp->b_flags & B_READ) != B_READ ||
  205             sc == NULL || !FSS_ISVALID(sc)) {
  206 
  207                 FSS_UNLOCK(sc, s);
  208 
  209                 bp->b_error = (sc == NULL ? ENODEV : EROFS);
  210                 bp->b_flags |= B_ERROR;
  211                 bp->b_resid = bp->b_bcount;
  212                 biodone(bp);
  213                 return;
  214         }
  215 
  216         bp->b_rawblkno = bp->b_blkno;
  217         BUFQ_PUT(&sc->sc_bufq, bp);
  218         wakeup(&sc->sc_bs_proc);
  219 
  220         FSS_UNLOCK(sc, s);
  221 }
  222 
  223 int
  224 fss_read(dev_t dev, struct uio *uio, int flags)
  225 {
  226         return physio(fss_strategy, NULL, dev, B_READ, minphys, uio);
  227 }
  228 
  229 int
  230 fss_write(dev_t dev, struct uio *uio, int flags)
  231 {
  232         return physio(fss_strategy, NULL, dev, B_WRITE, minphys, uio);
  233 }
  234 
  235 int
  236 fss_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
  237 {
  238         int s, error;
  239         struct fss_softc *sc;
  240         struct fss_set *fss = (struct fss_set *)data;
  241         struct fss_get *fsg = (struct fss_get *)data;
  242 
  243         if ((sc = FSS_DEV_TO_SOFTC(dev)) == NULL)
  244                 return ENODEV;
  245 
  246         FSS_LOCK(sc, s);
  247         while ((sc->sc_flags & FSS_EXCL) == FSS_EXCL) {
  248                 error = ltsleep(sc, PRIBIO|PCATCH, "fsslock", 0, &sc->sc_slock);
  249                 if (error) {
  250                         FSS_UNLOCK(sc, s);
  251                         return error;
  252                 }
  253         }
  254         sc->sc_flags |= FSS_EXCL;
  255         FSS_UNLOCK(sc, s);
  256 
  257         error = EINVAL;
  258 
  259         switch (cmd) {
  260         case FSSIOCSET:
  261                 if ((flag & FWRITE) == 0)
  262                         error = EPERM;
  263                 else if ((sc->sc_flags & FSS_ACTIVE) != 0)
  264                         error = EBUSY;
  265                 else
  266                         error = fss_create_snapshot(sc, fss, p);
  267                 break;
  268 
  269         case FSSIOCCLR:
  270                 if ((flag & FWRITE) == 0)
  271                         error = EPERM;
  272                 else if ((sc->sc_flags & FSS_ACTIVE) == 0)
  273                         error = ENXIO;
  274                 else
  275                         error = fss_delete_snapshot(sc, p);
  276                 break;
  277 
  278         case FSSIOCGET:
  279                 if ((sc->sc_flags & FSS_ACTIVE) == FSS_ACTIVE) {
  280                         memcpy(fsg->fsg_mount, sc->sc_mntname, MNAMELEN);
  281                         fsg->fsg_csize = FSS_CLSIZE(sc);
  282                         fsg->fsg_time = sc->sc_time;
  283                         fsg->fsg_mount_size = sc->sc_clcount;
  284                         fsg->fsg_bs_size = sc->sc_clnext;
  285                         error = 0;
  286                 } else
  287                         error = ENXIO;
  288                 break;
  289         }
  290 
  291         FSS_LOCK(sc, s);
  292         sc->sc_flags &= ~FSS_EXCL;
  293         FSS_UNLOCK(sc, s);
  294         wakeup(sc);
  295 
  296         return error;
  297 }
  298 
  299 int
  300 fss_size(dev_t dev)
  301 {
  302         return -1;
  303 }
  304 
  305 int
  306 fss_dump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
  307 {
  308         return EROFS;
  309 }
  310 
  311 /*
  312  * An error occurred reading or writing the snapshot or backing store.
  313  * If it is the first error log to console.
  314  * The caller holds the simplelock.
  315  */
  316 static inline void
  317 fss_error(struct fss_softc *sc, const char *fmt, ...)
  318 {
  319         va_list ap;
  320 
  321         if ((sc->sc_flags & (FSS_ACTIVE|FSS_ERROR)) == FSS_ACTIVE) {
  322                 va_start(ap, fmt);
  323                 printf("fss%d: snapshot invalid: ", sc->sc_unit);
  324                 vprintf(fmt, ap);
  325                 printf("\n");
  326                 va_end(ap);
  327         }
  328         if ((sc->sc_flags & FSS_ACTIVE) == FSS_ACTIVE)
  329                 sc->sc_flags |= FSS_ERROR;
  330 }
  331 
  332 /*
  333  * Allocate the variable sized parts of the softc and
  334  * fork the kernel thread.
  335  *
  336  * The fields sc_clcount, sc_clshift, sc_cache_size and sc_indir_size
  337  * must be initialized.
  338  */
  339 static int
  340 fss_softc_alloc(struct fss_softc *sc)
  341 {
  342         int i, len, error;
  343 
  344         len = (sc->sc_clcount+NBBY-1)/NBBY;
  345         sc->sc_copied = malloc(len, M_TEMP, M_ZERO|M_WAITOK|M_CANFAIL);
  346         if (sc->sc_copied == NULL)
  347                 return(ENOMEM);
  348 
  349         len = sc->sc_cache_size*sizeof(struct fss_cache);
  350         sc->sc_cache = malloc(len, M_TEMP, M_ZERO|M_WAITOK|M_CANFAIL);
  351         if (sc->sc_cache == NULL)
  352                 return(ENOMEM);
  353 
  354         len = FSS_CLSIZE(sc);
  355         for (i = 0; i < sc->sc_cache_size; i++) {
  356                 sc->sc_cache[i].fc_type = FSS_CACHE_FREE;
  357                 sc->sc_cache[i].fc_softc = sc;
  358                 sc->sc_cache[i].fc_xfercount = 0;
  359                 sc->sc_cache[i].fc_data = malloc(len, M_TEMP,
  360                     M_WAITOK|M_CANFAIL);
  361                 if (sc->sc_cache[i].fc_data == NULL)
  362                         return(ENOMEM);
  363         }
  364 
  365         len = (sc->sc_indir_size+NBBY-1)/NBBY;
  366         sc->sc_indir_valid = malloc(len, M_TEMP, M_ZERO|M_WAITOK|M_CANFAIL);
  367         if (sc->sc_indir_valid == NULL)
  368                 return(ENOMEM);
  369 
  370         len = FSS_CLSIZE(sc);
  371         sc->sc_indir_data = malloc(len, M_TEMP, M_ZERO|M_WAITOK|M_CANFAIL);
  372         if (sc->sc_indir_data == NULL)
  373                 return(ENOMEM);
  374 
  375         if ((error = kthread_create1(fss_bs_thread, sc, &sc->sc_bs_proc,
  376             "fssbs%d", sc->sc_unit)) != 0)
  377                 return error;
  378 
  379         sc->sc_flags |= FSS_BS_THREAD;
  380         return 0;
  381 }
  382 
  383 /*
  384  * Free the variable sized parts of the softc.
  385  */
  386 static void
  387 fss_softc_free(struct fss_softc *sc)
  388 {
  389         int s, i;
  390 
  391         if ((sc->sc_flags & FSS_BS_THREAD) != 0) {
  392                 FSS_LOCK(sc, s);
  393                 sc->sc_flags &= ~FSS_BS_THREAD;
  394                 wakeup(&sc->sc_bs_proc);
  395                 while (sc->sc_bs_proc != NULL)
  396                         ltsleep(&sc->sc_bs_proc, PRIBIO, "fssthread", 0,
  397                             &sc->sc_slock);
  398                 FSS_UNLOCK(sc, s);
  399         }
  400 
  401         if (sc->sc_copied != NULL)
  402                 free(sc->sc_copied, M_TEMP);
  403         sc->sc_copied = NULL;
  404 
  405         if (sc->sc_cache != NULL) {
  406                 for (i = 0; i < sc->sc_cache_size; i++)
  407                         if (sc->sc_cache[i].fc_data != NULL)
  408                                 free(sc->sc_cache[i].fc_data, M_TEMP);
  409                 free(sc->sc_cache, M_TEMP);
  410         }
  411         sc->sc_cache = NULL;
  412 
  413         if (sc->sc_indir_valid != NULL)
  414                 free(sc->sc_indir_valid, M_TEMP);
  415         sc->sc_indir_valid = NULL;
  416 
  417         if (sc->sc_indir_data != NULL)
  418                 free(sc->sc_indir_data, M_TEMP);
  419         sc->sc_indir_data = NULL;
  420 }
  421 
  422 /*
  423  * Check if an unmount is ok. If forced, set this snapshot into ERROR state.
  424  */
  425 int
  426 fss_umount_hook(struct mount *mp, int forced)
  427 {
  428         int i, s;
  429 
  430         for (i = 0; i < NFSS; i++) {
  431                 FSS_LOCK(&fss_softc[i], s);
  432                 if ((fss_softc[i].sc_flags & FSS_ACTIVE) != 0 &&
  433                     fss_softc[i].sc_mount == mp) {
  434                         if (forced)
  435                                 fss_error(&fss_softc[i], "forced unmount");
  436                         else {
  437                                 FSS_UNLOCK(&fss_softc[i], s);
  438                                 return EBUSY;
  439                         }
  440                 }
  441                 FSS_UNLOCK(&fss_softc[i], s);
  442         }
  443 
  444         return 0;
  445 }
  446 
  447 /*
  448  * A buffer is written to the snapshotted block device. Copy to
  449  * backing store if needed.
  450  */
  451 static void
  452 fss_copy_on_write(void *v, struct buf *bp)
  453 {
  454         int s;
  455         u_int32_t cl, ch, c;
  456         struct fss_softc *sc = v;
  457 
  458         FSS_LOCK(sc, s);
  459         if (!FSS_ISVALID(sc)) {
  460                 FSS_UNLOCK(sc, s);
  461                 return;
  462         }
  463 
  464         FSS_UNLOCK(sc, s);
  465 
  466         FSS_STAT_INC(sc, cow_calls);
  467 
  468         cl = FSS_BTOCL(sc, dbtob(bp->b_blkno));
  469         ch = FSS_BTOCL(sc, dbtob(bp->b_blkno)+bp->b_bcount-1);
  470 
  471         for (c = cl; c <= ch; c++)
  472                 fss_read_cluster(sc, c);
  473 }
  474 
  475 /*
  476  * Lookup and open needed files.
  477  *
  478  * Returns dev and size of the underlying block device.
  479  * Initializes sc_mntname, sc_mount_vp, sc_bdev, sc_bs_vp and sc_mount
  480  */
  481 static int
  482 fss_create_files(struct fss_softc *sc, struct fss_set *fss,
  483     off_t *bsize, struct proc *p)
  484 {
  485         int error, fsbsize;
  486         struct partinfo dpart;
  487         struct vattr va;
  488         struct nameidata nd;
  489 
  490         /*
  491          * Get the mounted file system.
  492          */
  493 
  494         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fss->fss_mount, p);
  495         if ((error = namei(&nd)) != 0)
  496                 return error;
  497 
  498         vrele(nd.ni_vp);
  499 
  500         if ((nd.ni_vp->v_flag & VROOT) != VROOT)
  501                 return EINVAL;
  502 
  503         sc->sc_mount = nd.ni_vp->v_mount;
  504 
  505         /*
  506          * Get the block device it is mounted on.
  507          */
  508 
  509         memcpy(sc->sc_mntname, sc->sc_mount->mnt_stat.f_mntonname, MNAMELEN); 
  510 
  511         NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE,
  512             sc->sc_mount->mnt_stat.f_mntfromname, p);
  513         if ((error = namei(&nd)) != 0)
  514                 return error;
  515 
  516         if (nd.ni_vp->v_type != VBLK) {
  517                 vrele(nd.ni_vp);
  518                 return EINVAL;
  519         }
  520 
  521         error = VOP_IOCTL(nd.ni_vp, DIOCGPART, &dpart, FREAD, p->p_ucred, p);
  522         if (error) {
  523                 vrele(nd.ni_vp);
  524                 return error;
  525         }
  526 
  527         sc->sc_mount_vp = nd.ni_vp;
  528         sc->sc_bdev = nd.ni_vp->v_rdev;
  529         *bsize = (off_t)dpart.disklab->d_secsize*dpart.part->p_size;
  530         vrele(nd.ni_vp);
  531 
  532         /*
  533          * Get the backing store
  534          */
  535 
  536         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fss->fss_bstore, p);
  537         if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0)
  538                 return error;
  539         VOP_UNLOCK(nd.ni_vp, 0);
  540 
  541         sc->sc_bs_vp = nd.ni_vp;
  542 
  543         if (nd.ni_vp->v_type != VREG && nd.ni_vp->v_type != VCHR)
  544                 return EINVAL;
  545 
  546         if (sc->sc_bs_vp->v_type == VREG) {
  547                 error = VOP_GETATTR(sc->sc_bs_vp, &va, p->p_ucred, p);
  548                 if (error != 0)
  549                         return error;
  550                 sc->sc_bs_size = va.va_size;
  551                 fsbsize = sc->sc_bs_vp->v_mount->mnt_stat.f_iosize;
  552                 if (fsbsize & (fsbsize-1))      /* No power of two */
  553                         return EINVAL;
  554                 for (sc->sc_bs_bshift = 1; sc->sc_bs_bshift < 32;
  555                     sc->sc_bs_bshift++)
  556                         if (FSS_FSBSIZE(sc) == fsbsize)
  557                                 break;
  558                 if (sc->sc_bs_bshift >= 32)
  559                         return EINVAL;
  560                 sc->sc_bs_bmask = FSS_FSBSIZE(sc)-1;
  561                 sc->sc_flags |= FSS_BS_ALLOC;
  562         } else {
  563                 sc->sc_bs_bshift = DEV_BSHIFT;
  564                 sc->sc_bs_bmask = FSS_FSBSIZE(sc)-1;
  565                 sc->sc_flags &= ~FSS_BS_ALLOC;
  566         }
  567 
  568         /*
  569          * As all IO to from/to the backing store goes through
  570          * VOP_STRATEGY() clean the buffer cache to prevent
  571          * cache incoherencies.
  572          */
  573         if ((error = vinvalbuf(sc->sc_bs_vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0)
  574                 return error;
  575 
  576         return 0;
  577 }
  578 
  579 /*
  580  * Create a snapshot.
  581  */
  582 static int
  583 fss_create_snapshot(struct fss_softc *sc, struct fss_set *fss, struct proc *p)
  584 {
  585         int len, error;
  586         u_int32_t csize;
  587         off_t bsize;
  588 
  589         /*
  590          * Open needed files.
  591          */
  592         if ((error = fss_create_files(sc, fss, &bsize, p)) != 0)
  593                 goto bad;
  594 
  595         if (sc->sc_bs_vp->v_type == VREG &&
  596             sc->sc_bs_vp->v_mount == sc->sc_mount) {
  597                 /* XXX need persistent snapshot inside the file system:
  598                  *  VFS_SNAPSHOT(sc->sc_mount, sc->sc_bs_vp);
  599                  *  sc->sc_time = xtime(sc->sc_bs_vp);
  600                  *  sc->sc_flags |= FSS_PERSISTENT;
  601                  *  fss_softc_alloc(sc);
  602                  *  sc->sc_flags |= FSS_ACTIVE;
  603                  */
  604                 error = EDEADLK;
  605                 goto bad;
  606         }
  607 
  608         /*
  609          * Set cluster size. Must be a power of two and
  610          * a multiple of backing store block size.
  611          */
  612         if (fss->fss_csize <= 0)
  613                 csize = MAXPHYS;
  614         else
  615                 csize = fss->fss_csize;
  616         if (bsize/csize > FSS_CLUSTER_MAX)
  617                 csize = bsize/FSS_CLUSTER_MAX+1;
  618 
  619         for (sc->sc_clshift = sc->sc_bs_bshift; sc->sc_clshift < 32;
  620             sc->sc_clshift++)
  621                 if (FSS_CLSIZE(sc) >= csize)
  622                         break;
  623         if (sc->sc_clshift >= 32) {
  624                 error = EINVAL;
  625                 goto bad;
  626         }
  627         sc->sc_clmask = FSS_CLSIZE(sc)-1;
  628 
  629         /*
  630          * Set number of cache slots.
  631          */
  632         if (FSS_CLSIZE(sc) <= 8192)
  633                 sc->sc_cache_size = 32;
  634         else if (FSS_CLSIZE(sc) <= 65536)
  635                 sc->sc_cache_size = 8;
  636         else
  637                 sc->sc_cache_size = 4;
  638 
  639         /*
  640          * Set number of clusters and size of last cluster.
  641          */
  642         sc->sc_clcount = FSS_BTOCL(sc, bsize-1)+1;
  643         sc->sc_clresid = FSS_CLOFF(sc, bsize-1)+1;
  644 
  645         /*
  646          * Set size of indirect table.
  647          */
  648         len = sc->sc_clcount*sizeof(u_int32_t);
  649         sc->sc_indir_size = FSS_BTOCL(sc, len)+1;
  650         sc->sc_clnext = sc->sc_indir_size;
  651         sc->sc_indir_cur = 0;
  652 
  653         if ((error = fss_softc_alloc(sc)) != 0)
  654                 goto bad;
  655 
  656         /*
  657          * Activate the snapshot.
  658          */
  659 
  660         if ((error = vfs_write_suspend(sc->sc_mount, PUSER|PCATCH, 0)) != 0)
  661                 goto bad;
  662 
  663         microtime(&sc->sc_time);
  664 
  665         if (error == 0)
  666                 error = vn_cow_establish(sc->sc_mount_vp,
  667                     fss_copy_on_write, sc);
  668         if (error == 0)
  669                 sc->sc_flags |= FSS_ACTIVE;
  670 
  671         vfs_write_resume(sc->sc_mount);
  672 
  673         if (error != 0)
  674                 goto bad;
  675 
  676 #ifdef DEBUG
  677         printf("fss%d: %s snapshot active\n", sc->sc_unit, sc->sc_mntname);
  678         printf("fss%d: %u clusters of %u, %u cache slots, %u indir clusters\n",
  679             sc->sc_unit, sc->sc_clcount, FSS_CLSIZE(sc),
  680             sc->sc_cache_size, sc->sc_indir_size);
  681 #endif
  682 
  683         return 0;
  684 
  685 bad:
  686         fss_softc_free(sc);
  687         if (sc->sc_bs_vp != NULL)
  688                 vn_close(sc->sc_bs_vp, FREAD|FWRITE, p->p_ucred, p);
  689         sc->sc_bs_vp = NULL;
  690 
  691         return error;
  692 }
  693 
  694 /*
  695  * Delete a snapshot.
  696  */
  697 static int
  698 fss_delete_snapshot(struct fss_softc *sc, struct proc *p)
  699 {
  700         int s;
  701 
  702         vn_cow_disestablish(sc->sc_mount_vp, fss_copy_on_write, sc);
  703 
  704         FSS_LOCK(sc, s);
  705         sc->sc_flags &= ~(FSS_ACTIVE|FSS_ERROR);
  706         sc->sc_mount = NULL;
  707         sc->sc_bdev = NODEV;
  708         FSS_UNLOCK(sc, s);
  709 
  710         fss_softc_free(sc);
  711         vn_close(sc->sc_bs_vp, FREAD|FWRITE, p->p_ucred, p);
  712         sc->sc_bs_vp = NULL;
  713 
  714         FSS_STAT_CLEAR(sc);
  715 
  716         return 0;
  717 }
  718 
  719 /*
  720  * Get the block address and number of contiguous blocks.
  721  * If the file contains a hole, try to allocate.
  722  */  
  723 static int
  724 fss_bmap(struct fss_softc *sc, off_t start, int len,
  725     struct vnode **vpp, daddr_t *bnp, int *runp)
  726 {
  727         int l, s, error;
  728         struct buf *bp, **bpp;
  729 
  730         if ((sc->sc_bs_vp->v_mount->mnt_flag & MNT_SOFTDEP) != 0)
  731                 bpp = &bp;
  732         else
  733                 bpp = NULL;
  734 
  735         vn_lock(sc->sc_bs_vp, LK_EXCLUSIVE|LK_RETRY);
  736 
  737         error = VOP_BMAP(sc->sc_bs_vp, FSS_BTOFSB(sc, start), vpp, bnp, runp);
  738         if ((error == 0 && *bnp != (daddr_t)-1) ||
  739             (sc->sc_flags & FSS_BS_ALLOC) == 0)
  740                 goto out;
  741 
  742         if (start+len >= sc->sc_bs_size) {
  743                 error = ENOSPC;
  744                 goto out;
  745         }
  746 
  747         for (l = 0; l < len; l += FSS_FSBSIZE(sc)) {
  748                 error = VOP_BALLOC(sc->sc_bs_vp, start+l, FSS_FSBSIZE(sc),
  749                     sc->sc_bs_proc->p_ucred, 0, bpp);
  750                 if (error)
  751                         goto out;
  752 
  753                 if (bpp == NULL)
  754                         continue;
  755 
  756                 s = splbio();
  757                 simple_lock(&bp->b_interlock);
  758 
  759                 if (LIST_FIRST(&bp->b_dep) != NULL && bioops.io_start)
  760                         (*bioops.io_start)(bp);
  761                 if (LIST_FIRST(&bp->b_dep) != NULL && bioops.io_complete)
  762                         (*bioops.io_complete)(bp);
  763 
  764                 bp->b_flags |= B_INVAL;
  765                 simple_unlock(&bp->b_interlock);
  766                 splx(s);
  767 
  768                 brelse(bp);
  769         }
  770 
  771         error = VOP_BMAP(sc->sc_bs_vp, FSS_BTOFSB(sc, start), vpp, bnp, runp);
  772 
  773 out:
  774 
  775         VOP_UNLOCK(sc->sc_bs_vp, 0);
  776         if (error == 0 && *bnp == (daddr_t)-1)
  777                 error = ENOSPC;
  778 
  779         return error;
  780 }
  781 
  782 /*
  783  * A read from the snapshotted block device has completed.
  784  */
  785 static void
  786 fss_cluster_iodone(struct buf *bp)
  787 {
  788         int s;
  789         struct fss_cache *scp = bp->b_private;
  790 
  791         FSS_LOCK(scp->fc_softc, s);
  792 
  793         if (bp->b_flags & B_EINTR)
  794                 fss_error(scp->fc_softc, "fs read interrupted");
  795         if (bp->b_flags & B_ERROR)
  796                 fss_error(scp->fc_softc, "fs read error %d", bp->b_error);
  797 
  798         if (bp->b_vp != NULL)
  799                 brelvp(bp);
  800 
  801         if (--scp->fc_xfercount == 0)
  802                 wakeup(&scp->fc_data);
  803 
  804         FSS_UNLOCK(scp->fc_softc, s);
  805 
  806         s = splbio();
  807         pool_put(&bufpool, bp);
  808         splx(s);
  809 }
  810 
  811 /*
  812  * Read a cluster from the snapshotted block device to the cache.
  813  */
  814 static void
  815 fss_read_cluster(struct fss_softc *sc, u_int32_t cl)
  816 {
  817         int s, todo, len;
  818         caddr_t addr;
  819         daddr_t dblk;
  820         struct buf *bp;
  821         struct fss_cache *scp, *scl;
  822 
  823         /*
  824          * Get a free cache slot.
  825          */
  826         scl = sc->sc_cache+sc->sc_cache_size;
  827 
  828         FSS_LOCK(sc, s);
  829 
  830 restart:
  831         if (isset(sc->sc_copied, cl) || !FSS_ISVALID(sc)) {
  832                 FSS_UNLOCK(sc, s);
  833                 return;
  834         }
  835 
  836         for (scp = sc->sc_cache; scp < scl; scp++)
  837                 if (scp->fc_type != FSS_CACHE_FREE &&
  838                     scp->fc_cluster == cl) {
  839                         ltsleep(&scp->fc_type, PRIBIO, "cowwait2", 0,
  840                             &sc->sc_slock);
  841                         goto restart;
  842                 }
  843 
  844         for (scp = sc->sc_cache; scp < scl; scp++)
  845                 if (scp->fc_type == FSS_CACHE_FREE) {
  846                         scp->fc_type = FSS_CACHE_BUSY;
  847                         scp->fc_cluster = cl;
  848                         break;
  849                 }
  850         if (scp >= scl) {
  851                 FSS_STAT_INC(sc, cow_cache_full);
  852                 ltsleep(&sc->sc_cache, PRIBIO, "cowwait3", 0, &sc->sc_slock);
  853                 goto restart;
  854         }
  855 
  856         FSS_UNLOCK(sc, s);
  857 
  858         /*
  859          * Start the read.
  860          */
  861         FSS_STAT_INC(sc, cow_copied);
  862 
  863         dblk = btodb(FSS_CLTOB(sc, cl));
  864         addr = scp->fc_data;
  865         if (cl == sc->sc_clcount-1) {
  866                 todo = sc->sc_clresid;
  867                 memset(addr+todo, 0, FSS_CLSIZE(sc)-todo);
  868         } else
  869                 todo = FSS_CLSIZE(sc);
  870         while (todo > 0) {
  871                 len = todo;
  872                 if (len > MAXPHYS)
  873                         len = MAXPHYS;
  874 
  875                 s = splbio();
  876                 bp = pool_get(&bufpool, PR_WAITOK);
  877                 splx(s);
  878 
  879                 BUF_INIT(bp);
  880                 bp->b_flags = B_READ|B_CALL;
  881                 bp->b_bcount = len;
  882                 bp->b_bufsize = bp->b_bcount;
  883                 bp->b_error = 0;
  884                 bp->b_data = addr;
  885                 bp->b_blkno = bp->b_rawblkno = dblk;
  886                 bp->b_proc = NULL;
  887                 bp->b_dev = sc->sc_bdev;
  888                 bp->b_vp = NULLVP;
  889                 bp->b_private = scp;
  890                 bp->b_iodone = fss_cluster_iodone;
  891 
  892                 DEV_STRATEGY(bp);
  893 
  894                 FSS_LOCK(sc, s);
  895                 scp->fc_xfercount++;
  896                 FSS_UNLOCK(sc, s);
  897 
  898                 dblk += btodb(len);
  899                 addr += len;
  900                 todo -= len;
  901         }
  902 
  903         /*
  904          * Wait for all read requests to complete.
  905          */
  906         FSS_LOCK(sc, s);
  907         while (scp->fc_xfercount > 0)
  908                 ltsleep(&scp->fc_data, PRIBIO, "cowwait", 0, &sc->sc_slock);
  909 
  910         scp->fc_type = FSS_CACHE_VALID;
  911         setbit(sc->sc_copied, scp->fc_cluster);
  912         FSS_UNLOCK(sc, s);
  913 
  914         wakeup(&sc->sc_bs_proc);
  915 }
  916 
  917 /*
  918  * Write a cluster from the cache to the backing store.
  919  */
  920 static int
  921 fss_write_cluster(struct fss_cache *scp, u_int32_t cl)
  922 {
  923         int s, error, todo, len, nra;
  924         daddr_t nbn;
  925         caddr_t addr;
  926         off_t pos;
  927         struct buf *bp;
  928         struct vnode *vp;
  929         struct fss_softc *sc;
  930 
  931         error = 0;
  932         sc = scp->fc_softc;
  933 
  934         pos = FSS_CLTOB(sc, cl);
  935         addr = scp->fc_data;
  936         todo = FSS_CLSIZE(sc);
  937 
  938         while (todo > 0) {
  939                 error = fss_bmap(sc, pos, todo, &vp, &nbn, &nra);
  940                 if (error)
  941                         break;
  942 
  943                 len = FSS_FSBTOB(sc, nra+1)-FSS_FSBOFF(sc, pos);
  944                 if (len > todo)
  945                         len = todo;
  946 
  947                 s = splbio();
  948                 bp = pool_get(&bufpool, PR_WAITOK);
  949                 splx(s);
  950 
  951                 BUF_INIT(bp);
  952                 bp->b_flags = B_CALL;
  953                 bp->b_bcount = len;
  954                 bp->b_bufsize = bp->b_bcount;
  955                 bp->b_error = 0;
  956                 bp->b_data = addr;
  957                 bp->b_blkno = bp->b_rawblkno = nbn+btodb(FSS_FSBOFF(sc, pos));
  958                 bp->b_proc = NULL;
  959                 bp->b_vp = NULLVP;
  960                 bp->b_private = scp;
  961                 bp->b_iodone = fss_cluster_iodone;
  962                 bgetvp(vp, bp);
  963                 bp->b_vp->v_numoutput++;
  964 
  965                 BIO_SETPRIO(bp, BPRIO_TIMECRITICAL);
  966                 VOP_STRATEGY(vp, bp);
  967 
  968                 FSS_LOCK(sc, s);
  969                 scp->fc_xfercount++;
  970                 FSS_UNLOCK(sc, s);
  971 
  972                 pos += len;
  973                 addr += len;
  974                 todo -= len;
  975         }
  976 
  977         /*
  978          * Wait for all write requests to complete.
  979          */
  980         FSS_LOCK(sc, s);
  981         while (scp->fc_xfercount > 0)
  982                 ltsleep(&scp->fc_data, PRIBIO, "bswwait", 0, &sc->sc_slock);
  983         FSS_UNLOCK(sc, s);
  984 
  985         return error;
  986 }
  987 
  988 /*
  989  * Read/write clusters from/to backing store.
  990  */
  991 static int
  992 fss_bs_io(struct fss_softc *sc, fss_io_type rw,
  993     u_int32_t cl, long off, int len, caddr_t data)
  994 {
  995         int s, error, todo, count, nra;
  996         off_t pos;
  997         daddr_t nbn;
  998         struct buf *bp;
  999         struct vnode *vp;
 1000 
 1001         todo = len;
 1002         pos = FSS_CLTOB(sc, cl)+off;
 1003         error = 0;
 1004 
 1005         while (todo > 0) {
 1006                 error = fss_bmap(sc, pos, todo, &vp, &nbn, &nra);
 1007                 if (error)
 1008                         break;
 1009 
 1010                 count = FSS_FSBTOB(sc, nra+1)-FSS_FSBOFF(sc, pos);
 1011                 if (count > todo)
 1012                         count = todo;
 1013 
 1014                 s = splbio();
 1015                 bp = pool_get(&bufpool, PR_WAITOK);
 1016                 splx(s);
 1017 
 1018                 BUF_INIT(bp);
 1019                 bp->b_flags = (rw == FSS_READ ? B_READ : 0);
 1020                 bp->b_bcount = count;
 1021                 bp->b_bufsize = bp->b_bcount;
 1022                 bp->b_error = 0;
 1023                 bp->b_data = data;
 1024                 bp->b_blkno = bp->b_rawblkno = nbn+btodb(FSS_FSBOFF(sc, pos));
 1025                 bp->b_proc = NULL;
 1026                 bp->b_vp = NULLVP;
 1027                 bgetvp(vp, bp);
 1028                 if ((bp->b_flags & B_READ) == 0)
 1029                         bp->b_vp->v_numoutput++;
 1030 
 1031                 if ((bp->b_flags & B_READ) == 0 || cl < sc->sc_indir_size)
 1032                         BIO_SETPRIO(bp, BPRIO_TIMECRITICAL);
 1033                 VOP_STRATEGY(vp, bp);
 1034 
 1035                 error = biowait(bp);
 1036 
 1037                 if (bp->b_vp != NULL)
 1038                         brelvp(bp);
 1039 
 1040                 s = splbio();
 1041                 pool_put(&bufpool, bp);
 1042                 splx(s);
 1043 
 1044                 if (error)
 1045                         break;
 1046 
 1047                 todo -= count;
 1048                 data += count;
 1049                 pos += count;
 1050         }
 1051 
 1052         return error;           
 1053 }
 1054 
 1055 /*
 1056  * Get a pointer to the indirect slot for this cluster.
 1057  */
 1058 static u_int32_t *
 1059 fss_bs_indir(struct fss_softc *sc, u_int32_t cl)
 1060 {
 1061         u_int32_t icl;
 1062         int ioff;
 1063 
 1064         icl = cl/(FSS_CLSIZE(sc)/sizeof(u_int32_t));
 1065         ioff = cl%(FSS_CLSIZE(sc)/sizeof(u_int32_t));
 1066 
 1067         if (sc->sc_indir_cur == icl)
 1068                 return &sc->sc_indir_data[ioff];
 1069 
 1070         if (sc->sc_indir_dirty) {
 1071                 FSS_STAT_INC(sc, indir_write);
 1072                 if (fss_bs_io(sc, FSS_WRITE, sc->sc_indir_cur, 0,
 1073                     FSS_CLSIZE(sc), (caddr_t)sc->sc_indir_data) != 0)
 1074                         return NULL;
 1075                 setbit(sc->sc_indir_valid, sc->sc_indir_cur);
 1076         }
 1077 
 1078         sc->sc_indir_dirty = 0;
 1079         sc->sc_indir_cur = icl;
 1080 
 1081         if (isset(sc->sc_indir_valid, sc->sc_indir_cur)) {
 1082                 FSS_STAT_INC(sc, indir_read);
 1083                 if (fss_bs_io(sc, FSS_READ, sc->sc_indir_cur, 0,
 1084                     FSS_CLSIZE(sc), (caddr_t)sc->sc_indir_data) != 0)
 1085                         return NULL;
 1086         } else
 1087                 memset(sc->sc_indir_data, 0, FSS_CLSIZE(sc));
 1088 
 1089         return &sc->sc_indir_data[ioff];
 1090 }
 1091 
 1092 /*
 1093  * The kernel thread (one for every active snapshot).
 1094  *
 1095  * After wakeup it cleans the cache and runs the I/O requests.
 1096  */
 1097 static void
 1098 fss_bs_thread(void *arg)
 1099 {
 1100         int error, len, nfreed, nio, s;
 1101         long off;
 1102         caddr_t addr;
 1103         u_int32_t c, cl, ch, *indirp;
 1104         struct buf *bp, *nbp;
 1105         struct fss_softc *sc;
 1106         struct fss_cache *scp, *scl;
 1107 
 1108         sc = arg;
 1109 
 1110         scl = sc->sc_cache+sc->sc_cache_size;
 1111 
 1112         s = splbio();
 1113         nbp = pool_get(&bufpool, PR_WAITOK);
 1114         splx(s);
 1115 
 1116         nfreed = nio = 1;               /* Dont sleep the first time */
 1117 
 1118         FSS_LOCK(sc, s);
 1119 
 1120         for (;;) {
 1121                 if (nfreed == 0 && nio == 0)
 1122                         ltsleep(&sc->sc_bs_proc, PVM-1, "fssbs", 0,
 1123                             &sc->sc_slock);
 1124 
 1125                 if ((sc->sc_flags & FSS_BS_THREAD) == 0) {
 1126                         sc->sc_bs_proc = NULL;
 1127                         wakeup(&sc->sc_bs_proc);
 1128 
 1129                         FSS_UNLOCK(sc, s);
 1130 
 1131                         s = splbio();
 1132                         pool_put(&bufpool, nbp);
 1133                         splx(s);
 1134 #ifdef FSS_STATISTICS
 1135                         printf("fss%d: cow called %" PRId64 " times,"
 1136                             " copied %" PRId64 " clusters,"
 1137                             " cache full %" PRId64 " times\n",
 1138                             sc->sc_unit,
 1139                             FSS_STAT_VAL(sc, cow_calls),
 1140                             FSS_STAT_VAL(sc, cow_copied),
 1141                             FSS_STAT_VAL(sc, cow_cache_full));
 1142                         printf("fss%d: %" PRId64 " indir reads,"
 1143                             " %" PRId64 " indir writes\n",
 1144                             sc->sc_unit,
 1145                             FSS_STAT_VAL(sc, indir_read),
 1146                             FSS_STAT_VAL(sc, indir_write));
 1147 #endif /* FSS_STATISTICS */
 1148                         kthread_exit(0);
 1149                 }
 1150 
 1151                 /*
 1152                  * Clean the cache
 1153                  */
 1154                 nfreed = 0;
 1155                 for (scp = sc->sc_cache; scp < scl; scp++) {
 1156                         if (scp->fc_type != FSS_CACHE_VALID)
 1157                                 continue;
 1158 
 1159                         FSS_UNLOCK(sc, s);
 1160 
 1161                         indirp = fss_bs_indir(sc, scp->fc_cluster);
 1162                         if (indirp != NULL) {
 1163                                 error = fss_write_cluster(scp, sc->sc_clnext);
 1164                         } else
 1165                                 error = EIO;
 1166 
 1167                         FSS_LOCK(sc, s);
 1168 
 1169                         if (error == 0) {
 1170                                 *indirp = sc->sc_clnext++;
 1171                                 sc->sc_indir_dirty = 1;
 1172                         } else
 1173                                 fss_error(sc, "write bs error %d", error);
 1174 
 1175                         scp->fc_type = FSS_CACHE_FREE;
 1176                         nfreed++;
 1177                         wakeup(&scp->fc_type);
 1178                 }
 1179 
 1180                 if (nfreed)
 1181                         wakeup(&sc->sc_cache);
 1182 
 1183                 /*
 1184                  * Process I/O requests
 1185                  */
 1186                 nio = 0;
 1187 
 1188                 if ((bp = BUFQ_GET(&sc->sc_bufq)) == NULL)
 1189                         continue;
 1190 
 1191                 nio++;
 1192 
 1193                 if (!FSS_ISVALID(sc)) {
 1194                         bp->b_error = ENXIO;
 1195                         bp->b_flags |= B_ERROR;
 1196                         bp->b_resid = bp->b_bcount;
 1197                         biodone(bp);
 1198                         continue;
 1199                 }
 1200 
 1201                 /*
 1202                  * First read from the snapshotted block device.
 1203                  * XXX Split to only read those parts that have not
 1204                  * been saved to backing store?
 1205                  */
 1206 
 1207                 FSS_UNLOCK(sc, s);
 1208 
 1209                 BUF_INIT(nbp);
 1210                 nbp->b_flags = B_READ;
 1211                 nbp->b_bcount = bp->b_bcount;
 1212                 nbp->b_bufsize = bp->b_bcount;
 1213                 nbp->b_error = 0;
 1214                 nbp->b_data = bp->b_data;
 1215                 nbp->b_blkno = nbp->b_rawblkno = bp->b_blkno;
 1216                 nbp->b_proc = bp->b_proc;
 1217                 nbp->b_dev = sc->sc_bdev;
 1218                 nbp->b_vp = NULLVP;
 1219 
 1220                 DEV_STRATEGY(nbp);
 1221 
 1222                 if (biowait(nbp) != 0) {
 1223                         bp->b_resid = bp->b_bcount;
 1224                         bp->b_error = nbp->b_error;
 1225                         bp->b_flags |= B_ERROR;
 1226                         biodone(bp);
 1227                         continue;
 1228                 }
 1229 
 1230                 cl = FSS_BTOCL(sc, dbtob(bp->b_blkno));
 1231                 off = FSS_CLOFF(sc, dbtob(bp->b_blkno));
 1232                 ch = FSS_BTOCL(sc, dbtob(bp->b_blkno)+bp->b_bcount-1);
 1233                 bp->b_resid = bp->b_bcount;
 1234                 addr = bp->b_data;
 1235 
 1236                 FSS_LOCK(sc, s);
 1237 
 1238                 /*
 1239                  * Replace those parts that have been saved to backing store.
 1240                  */
 1241 
 1242                 for (c = cl; c <= ch;
 1243                     c++, off = 0, bp->b_resid -= len, addr += len) {
 1244                         len = FSS_CLSIZE(sc)-off;
 1245                         if (len > bp->b_resid)
 1246                                 len = bp->b_resid;
 1247 
 1248                         if (isclr(sc->sc_copied, c))
 1249                                 continue;
 1250 
 1251                         FSS_UNLOCK(sc, s);
 1252 
 1253                         indirp = fss_bs_indir(sc, c);
 1254 
 1255                         FSS_LOCK(sc, s);
 1256 
 1257                         if (indirp == NULL || *indirp == 0) {
 1258                                 /*
 1259                                  * Not on backing store. Either in cache
 1260                                  * or hole in the snapshotted block device.
 1261                                  */
 1262                                 for (scp = sc->sc_cache; scp < scl; scp++)
 1263                                         if (scp->fc_type == FSS_CACHE_VALID &&
 1264                                             scp->fc_cluster == c)
 1265                                                 break;
 1266                                 if (scp < scl)
 1267                                         memcpy(addr, scp->fc_data+off, len);
 1268                                 else
 1269                                         memset(addr, 0, len);
 1270                                 continue;
 1271                         }
 1272                         /*
 1273                          * Read from backing store.
 1274                          */
 1275 
 1276                         FSS_UNLOCK(sc, s);
 1277 
 1278                         if ((error = fss_bs_io(sc, FSS_READ, *indirp,
 1279                             off, len, addr)) != 0) {
 1280                                 bp->b_resid = bp->b_bcount;
 1281                                 bp->b_error = error;
 1282                                 bp->b_flags |= B_ERROR;
 1283                                 break;
 1284                         }
 1285 
 1286                         FSS_LOCK(sc, s);
 1287 
 1288                 }
 1289 
 1290                 biodone(bp);
 1291         }
 1292 }

Cache object: 53ed90a1dcc9d495e0b84479263c1dfa


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.