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.29.2.1 2007/03/04 14:26:51 bouyer 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.29.2.1 2007/03/04 14:26:51 bouyer 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 int 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 lwp *);
  132 static int fss_create_snapshot(struct fss_softc *, struct fss_set *,
  133     struct lwp *);
  134 static int fss_delete_snapshot(struct fss_softc *, struct lwp *);
  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 void fss_bs_thread(void *);
  140 static int fss_bs_io(struct fss_softc *, fss_io_type,
  141     u_int32_t, off_t, int, caddr_t);
  142 static u_int32_t *fss_bs_indir(struct fss_softc *, u_int32_t);
  143 
  144 const struct bdevsw fss_bdevsw = {
  145         fss_open, fss_close, fss_strategy, fss_ioctl,
  146         fss_dump, fss_size, D_DISK
  147 };
  148 
  149 const struct cdevsw fss_cdevsw = {
  150         fss_open, fss_close, fss_read, fss_write, fss_ioctl,
  151         nostop, notty, nopoll, nommap, nokqfilter, D_DISK
  152 };
  153 
  154 void
  155 fssattach(int num)
  156 {
  157         int i;
  158         struct fss_softc *sc;
  159 
  160         for (i = 0; i < NFSS; i++) {
  161                 sc = &fss_softc[i];
  162                 sc->sc_unit = i;
  163                 sc->sc_bdev = NODEV;
  164                 simple_lock_init(&sc->sc_slock);
  165                 lockinit(&sc->sc_lock, PRIBIO, "fsslock", 0, 0);
  166                 bufq_alloc(&sc->sc_bufq, "fcfs", 0);
  167         }
  168 }
  169 
  170 int
  171 fss_open(dev_t dev, int flags, int mode, struct lwp *l)
  172 {
  173         int s, mflag;
  174         struct fss_softc *sc;
  175 
  176         mflag = (mode == S_IFCHR ? FSS_CDEV_OPEN : FSS_BDEV_OPEN);
  177 
  178         if ((sc = FSS_DEV_TO_SOFTC(dev)) == NULL)
  179                 return ENODEV;
  180 
  181         FSS_LOCK(sc, s);
  182 
  183         sc->sc_flags |= mflag;
  184 
  185         FSS_UNLOCK(sc, s);
  186 
  187         return 0;
  188 }
  189 
  190 int
  191 fss_close(dev_t dev, int flags, int mode, struct lwp *l)
  192 {
  193         int s, mflag, error;
  194         struct fss_softc *sc;
  195 
  196         mflag = (mode == S_IFCHR ? FSS_CDEV_OPEN : FSS_BDEV_OPEN);
  197 
  198         if ((sc = FSS_DEV_TO_SOFTC(dev)) == NULL)
  199                 return ENODEV;
  200 
  201         FSS_LOCK(sc, s); 
  202 
  203         if ((sc->sc_flags & (FSS_CDEV_OPEN|FSS_BDEV_OPEN)) == mflag) {
  204                 if ((sc->sc_uflags & FSS_UNCONFIG_ON_CLOSE) != 0 &&
  205                     (sc->sc_flags & FSS_ACTIVE) != 0) {
  206                         FSS_UNLOCK(sc, s);
  207                         error = fss_ioctl(dev, FSSIOCCLR, NULL, FWRITE, l);
  208                         if (error)
  209                                 return error;
  210                         FSS_LOCK(sc, s);
  211                 }
  212                 sc->sc_uflags &= ~FSS_UNCONFIG_ON_CLOSE;
  213         }
  214 
  215         sc->sc_flags &= ~mflag;
  216 
  217         FSS_UNLOCK(sc, s);
  218 
  219         return 0;
  220 }
  221 
  222 void
  223 fss_strategy(struct buf *bp)
  224 {
  225         int s;
  226         struct fss_softc *sc;
  227 
  228         sc = FSS_DEV_TO_SOFTC(bp->b_dev);
  229 
  230         FSS_LOCK(sc, s);
  231 
  232         if ((bp->b_flags & B_READ) != B_READ ||
  233             sc == NULL || !FSS_ISVALID(sc)) {
  234 
  235                 FSS_UNLOCK(sc, s);
  236 
  237                 bp->b_error = (sc == NULL ? ENODEV : EROFS);
  238                 bp->b_flags |= B_ERROR;
  239                 bp->b_resid = bp->b_bcount;
  240                 biodone(bp);
  241                 return;
  242         }
  243 
  244         bp->b_rawblkno = bp->b_blkno;
  245         BUFQ_PUT(sc->sc_bufq, bp);
  246         wakeup(&sc->sc_bs_proc);
  247 
  248         FSS_UNLOCK(sc, s);
  249 }
  250 
  251 int
  252 fss_read(dev_t dev, struct uio *uio, int flags)
  253 {
  254         return physio(fss_strategy, NULL, dev, B_READ, minphys, uio);
  255 }
  256 
  257 int
  258 fss_write(dev_t dev, struct uio *uio, int flags)
  259 {
  260         return physio(fss_strategy, NULL, dev, B_WRITE, minphys, uio);
  261 }
  262 
  263 int
  264 fss_ioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l)
  265 {
  266         int error;
  267         struct fss_softc *sc;
  268         struct fss_set *fss = (struct fss_set *)data;
  269         struct fss_get *fsg = (struct fss_get *)data;
  270 
  271         if ((sc = FSS_DEV_TO_SOFTC(dev)) == NULL)
  272                 return ENODEV;
  273 
  274         switch (cmd) {
  275         case FSSIOCSET:
  276                 lockmgr(&sc->sc_lock, LK_EXCLUSIVE, NULL);
  277                 if ((flag & FWRITE) == 0)
  278                         error = EPERM;
  279                 else if ((sc->sc_flags & FSS_ACTIVE) != 0)
  280                         error = EBUSY;
  281                 else
  282                         error = fss_create_snapshot(sc, fss, l);
  283                 lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
  284                 break;
  285 
  286         case FSSIOCCLR:
  287                 lockmgr(&sc->sc_lock, LK_EXCLUSIVE, NULL);
  288                 if ((flag & FWRITE) == 0)
  289                         error = EPERM;
  290                 else if ((sc->sc_flags & FSS_ACTIVE) == 0)
  291                         error = ENXIO;
  292                 else
  293                         error = fss_delete_snapshot(sc, l);
  294                 lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
  295                 break;
  296 
  297         case FSSIOCGET:
  298                 lockmgr(&sc->sc_lock, LK_EXCLUSIVE, NULL);
  299                 switch (sc->sc_flags & (FSS_PERSISTENT | FSS_ACTIVE)) {
  300                 case FSS_ACTIVE:
  301                         memcpy(fsg->fsg_mount, sc->sc_mntname, MNAMELEN);
  302                         fsg->fsg_csize = FSS_CLSIZE(sc);
  303                         fsg->fsg_time = sc->sc_time;
  304                         fsg->fsg_mount_size = sc->sc_clcount;
  305                         fsg->fsg_bs_size = sc->sc_clnext;
  306                         error = 0;
  307                         break;
  308                 case FSS_PERSISTENT | FSS_ACTIVE:
  309                         memcpy(fsg->fsg_mount, sc->sc_mntname, MNAMELEN);
  310                         fsg->fsg_csize = 0;
  311                         fsg->fsg_time = sc->sc_time;
  312                         fsg->fsg_mount_size = 0;
  313                         fsg->fsg_bs_size = 0;
  314                         error = 0;
  315                         break;
  316                 default:
  317                         error = ENXIO;
  318                         break;
  319                 }
  320                 lockmgr(&sc->sc_lock, LK_RELEASE, NULL);
  321                 break;
  322 
  323         case FSSIOFSET:
  324                 sc->sc_uflags = *(int *)data;
  325                 error = 0;
  326                 break;
  327 
  328         case FSSIOFGET:
  329                 *(int *)data = sc->sc_uflags;
  330                 error = 0;
  331                 break;
  332 
  333         default:
  334                 error = EINVAL;
  335                 break;
  336         }
  337 
  338         return error;
  339 }
  340 
  341 int
  342 fss_size(dev_t dev)
  343 {
  344         return -1;
  345 }
  346 
  347 int
  348 fss_dump(dev_t dev, daddr_t blkno, caddr_t va,
  349     size_t size)
  350 {
  351         return EROFS;
  352 }
  353 
  354 /*
  355  * An error occurred reading or writing the snapshot or backing store.
  356  * If it is the first error log to console.
  357  * The caller holds the simplelock.
  358  */
  359 static inline void
  360 fss_error(struct fss_softc *sc, const char *fmt, ...)
  361 {
  362         va_list ap;
  363 
  364         if ((sc->sc_flags & (FSS_ACTIVE|FSS_ERROR)) == FSS_ACTIVE) {
  365                 va_start(ap, fmt);
  366                 printf("fss%d: snapshot invalid: ", sc->sc_unit);
  367                 vprintf(fmt, ap);
  368                 printf("\n");
  369                 va_end(ap);
  370         }
  371         if ((sc->sc_flags & FSS_ACTIVE) == FSS_ACTIVE)
  372                 sc->sc_flags |= FSS_ERROR;
  373 }
  374 
  375 /*
  376  * Allocate the variable sized parts of the softc and
  377  * fork the kernel thread.
  378  *
  379  * The fields sc_clcount, sc_clshift, sc_cache_size and sc_indir_size
  380  * must be initialized.
  381  */
  382 static int
  383 fss_softc_alloc(struct fss_softc *sc)
  384 {
  385         int i, len, error;
  386 
  387         len = (sc->sc_clcount+NBBY-1)/NBBY;
  388         sc->sc_copied = malloc(len, M_TEMP, M_ZERO|M_WAITOK|M_CANFAIL);
  389         if (sc->sc_copied == NULL)
  390                 return(ENOMEM);
  391 
  392         len = sc->sc_cache_size*sizeof(struct fss_cache);
  393         sc->sc_cache = malloc(len, M_TEMP, M_ZERO|M_WAITOK|M_CANFAIL);
  394         if (sc->sc_cache == NULL)
  395                 return(ENOMEM);
  396 
  397         len = FSS_CLSIZE(sc);
  398         for (i = 0; i < sc->sc_cache_size; i++) {
  399                 sc->sc_cache[i].fc_type = FSS_CACHE_FREE;
  400                 sc->sc_cache[i].fc_softc = sc;
  401                 sc->sc_cache[i].fc_xfercount = 0;
  402                 sc->sc_cache[i].fc_data = malloc(len, M_TEMP,
  403                     M_WAITOK|M_CANFAIL);
  404                 if (sc->sc_cache[i].fc_data == NULL)
  405                         return(ENOMEM);
  406         }
  407 
  408         len = (sc->sc_indir_size+NBBY-1)/NBBY;
  409         sc->sc_indir_valid = malloc(len, M_TEMP, M_ZERO|M_WAITOK|M_CANFAIL);
  410         if (sc->sc_indir_valid == NULL)
  411                 return(ENOMEM);
  412 
  413         len = FSS_CLSIZE(sc);
  414         sc->sc_indir_data = malloc(len, M_TEMP, M_ZERO|M_WAITOK|M_CANFAIL);
  415         if (sc->sc_indir_data == NULL)
  416                 return(ENOMEM);
  417 
  418         if ((error = kthread_create1(fss_bs_thread, sc, &sc->sc_bs_proc,
  419             "fssbs%d", sc->sc_unit)) != 0)
  420                 return error;
  421 
  422         sc->sc_flags |= FSS_BS_THREAD;
  423         return 0;
  424 }
  425 
  426 /*
  427  * Free the variable sized parts of the softc.
  428  */
  429 static void
  430 fss_softc_free(struct fss_softc *sc)
  431 {
  432         int s, i;
  433 
  434         if ((sc->sc_flags & FSS_BS_THREAD) != 0) {
  435                 FSS_LOCK(sc, s);
  436                 sc->sc_flags &= ~FSS_BS_THREAD;
  437                 wakeup(&sc->sc_bs_proc);
  438                 while (sc->sc_bs_proc != NULL)
  439                         ltsleep(&sc->sc_bs_proc, PRIBIO, "fssthread", 0,
  440                             &sc->sc_slock);
  441                 FSS_UNLOCK(sc, s);
  442         }
  443 
  444         if (sc->sc_copied != NULL)
  445                 free(sc->sc_copied, M_TEMP);
  446         sc->sc_copied = NULL;
  447 
  448         if (sc->sc_cache != NULL) {
  449                 for (i = 0; i < sc->sc_cache_size; i++)
  450                         if (sc->sc_cache[i].fc_data != NULL)
  451                                 free(sc->sc_cache[i].fc_data, M_TEMP);
  452                 free(sc->sc_cache, M_TEMP);
  453         }
  454         sc->sc_cache = NULL;
  455 
  456         if (sc->sc_indir_valid != NULL)
  457                 free(sc->sc_indir_valid, M_TEMP);
  458         sc->sc_indir_valid = NULL;
  459 
  460         if (sc->sc_indir_data != NULL)
  461                 free(sc->sc_indir_data, M_TEMP);
  462         sc->sc_indir_data = NULL;
  463 }
  464 
  465 /*
  466  * Check if an unmount is ok. If forced, set this snapshot into ERROR state.
  467  */
  468 int
  469 fss_umount_hook(struct mount *mp, int forced)
  470 {
  471         int i, s;
  472 
  473         for (i = 0; i < NFSS; i++) {
  474                 FSS_LOCK(&fss_softc[i], s);
  475                 if ((fss_softc[i].sc_flags & FSS_ACTIVE) != 0 &&
  476                     fss_softc[i].sc_mount == mp) {
  477                         if (forced)
  478                                 fss_error(&fss_softc[i], "forced unmount");
  479                         else {
  480                                 FSS_UNLOCK(&fss_softc[i], s);
  481                                 return EBUSY;
  482                         }
  483                 }
  484                 FSS_UNLOCK(&fss_softc[i], s);
  485         }
  486 
  487         return 0;
  488 }
  489 
  490 /*
  491  * A buffer is written to the snapshotted block device. Copy to
  492  * backing store if needed.
  493  */
  494 static int
  495 fss_copy_on_write(void *v, struct buf *bp)
  496 {
  497         int s;
  498         u_int32_t cl, ch, c;
  499         struct fss_softc *sc = v;
  500 
  501         FSS_LOCK(sc, s);
  502         if (!FSS_ISVALID(sc)) {
  503                 FSS_UNLOCK(sc, s);
  504                 return 0;
  505         }
  506 
  507         FSS_UNLOCK(sc, s);
  508 
  509         FSS_STAT_INC(sc, cow_calls);
  510 
  511         cl = FSS_BTOCL(sc, dbtob(bp->b_blkno));
  512         ch = FSS_BTOCL(sc, dbtob(bp->b_blkno)+bp->b_bcount-1);
  513 
  514         for (c = cl; c <= ch; c++)
  515                 fss_read_cluster(sc, c);
  516 
  517         return 0;
  518 }
  519 
  520 /*
  521  * Lookup and open needed files.
  522  *
  523  * For file system internal snapshot initializes sc_mntname, sc_mount,
  524  * sc_bs_vp and sc_time.
  525  *
  526  * Otherwise returns dev and size of the underlying block device.
  527  * Initializes sc_mntname, sc_mount_vp, sc_bdev, sc_bs_vp and sc_mount
  528  */
  529 static int
  530 fss_create_files(struct fss_softc *sc, struct fss_set *fss,
  531     off_t *bsize, struct lwp *l)
  532 {
  533         int error, bits, fsbsize;
  534         struct timespec ts;
  535         struct partinfo dpart;
  536         struct vattr va;
  537         struct nameidata nd;
  538 
  539         /*
  540          * Get the mounted file system.
  541          */
  542 
  543         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fss->fss_mount, l);
  544         if ((error = namei(&nd)) != 0)
  545                 return error;
  546 
  547         if ((nd.ni_vp->v_flag & VROOT) != VROOT) {
  548                 vrele(nd.ni_vp);
  549                 return EINVAL;
  550         }
  551 
  552         sc->sc_mount = nd.ni_vp->v_mount;
  553         memcpy(sc->sc_mntname, sc->sc_mount->mnt_stat.f_mntonname, MNAMELEN);
  554 
  555         vrele(nd.ni_vp);
  556 
  557         /*
  558          * Check for file system internal snapshot.
  559          */
  560 
  561         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fss->fss_bstore, l);
  562         if ((error = namei(&nd)) != 0)
  563                 return error;
  564 
  565         if (nd.ni_vp->v_type == VREG && nd.ni_vp->v_mount == sc->sc_mount) {
  566                 vrele(nd.ni_vp);
  567                 sc->sc_flags |= FSS_PERSISTENT;
  568 
  569                 NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fss->fss_bstore, l);
  570                 if ((error = vn_open(&nd, FREAD, 0)) != 0)
  571                         return error;
  572                 sc->sc_bs_vp = nd.ni_vp;
  573 
  574                 fsbsize = sc->sc_bs_vp->v_mount->mnt_stat.f_iosize;
  575                 bits = sizeof(sc->sc_bs_bshift)*NBBY;
  576                 for (sc->sc_bs_bshift = 1; sc->sc_bs_bshift < bits;
  577                     sc->sc_bs_bshift++)
  578                         if (FSS_FSBSIZE(sc) == fsbsize)
  579                                 break;
  580                 if (sc->sc_bs_bshift >= bits) {
  581                         VOP_UNLOCK(sc->sc_bs_vp, 0);
  582                         return EINVAL;
  583                 }
  584 
  585                 sc->sc_bs_bmask = FSS_FSBSIZE(sc)-1;
  586                 sc->sc_clshift = 0;
  587 
  588                 error = VFS_SNAPSHOT(sc->sc_mount, sc->sc_bs_vp, &ts);
  589                 TIMESPEC_TO_TIMEVAL(&sc->sc_time, &ts);
  590 
  591                 VOP_UNLOCK(sc->sc_bs_vp, 0);
  592 
  593                 return error;
  594         }
  595         vrele(nd.ni_vp);
  596 
  597         /*
  598          * Get the block device it is mounted on.
  599          */
  600 
  601         NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE,
  602             sc->sc_mount->mnt_stat.f_mntfromname, l);
  603         if ((error = namei(&nd)) != 0)
  604                 return error;
  605 
  606         if (nd.ni_vp->v_type != VBLK) {
  607                 vrele(nd.ni_vp);
  608                 return EINVAL;
  609         }
  610 
  611         error = VOP_IOCTL(nd.ni_vp, DIOCGPART, &dpart, FREAD,
  612             l->l_cred, l);
  613         if (error) {
  614                 vrele(nd.ni_vp);
  615                 return error;
  616         }
  617 
  618         sc->sc_mount_vp = nd.ni_vp;
  619         sc->sc_bdev = nd.ni_vp->v_rdev;
  620         *bsize = (off_t)dpart.disklab->d_secsize*dpart.part->p_size;
  621         vrele(nd.ni_vp);
  622 
  623         /*
  624          * Get the backing store
  625          */
  626 
  627         NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fss->fss_bstore, l);
  628         if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0)
  629                 return error;
  630         VOP_UNLOCK(nd.ni_vp, 0);
  631 
  632         sc->sc_bs_vp = nd.ni_vp;
  633 
  634         if (nd.ni_vp->v_type != VREG && nd.ni_vp->v_type != VCHR)
  635                 return EINVAL;
  636 
  637         if (sc->sc_bs_vp->v_type == VREG) {
  638                 error = VOP_GETATTR(sc->sc_bs_vp, &va, l->l_cred, l);
  639                 if (error != 0)
  640                         return error;
  641                 sc->sc_bs_size = va.va_size;
  642                 fsbsize = sc->sc_bs_vp->v_mount->mnt_stat.f_iosize;
  643                 if (fsbsize & (fsbsize-1))      /* No power of two */
  644                         return EINVAL;
  645                 for (sc->sc_bs_bshift = 1; sc->sc_bs_bshift < 32;
  646                     sc->sc_bs_bshift++)
  647                         if (FSS_FSBSIZE(sc) == fsbsize)
  648                                 break;
  649                 if (sc->sc_bs_bshift >= 32)
  650                         return EINVAL;
  651                 sc->sc_bs_bmask = FSS_FSBSIZE(sc)-1;
  652         } else {
  653                 sc->sc_bs_bshift = DEV_BSHIFT;
  654                 sc->sc_bs_bmask = FSS_FSBSIZE(sc)-1;
  655         }
  656 
  657         /*
  658          * As all IO to from/to the backing store goes through
  659          * VOP_STRATEGY() clean the buffer cache to prevent
  660          * cache incoherencies.
  661          */
  662         if ((error = vinvalbuf(sc->sc_bs_vp, V_SAVE, l->l_cred, l, 0, 0)) != 0)
  663                 return error;
  664 
  665         return 0;
  666 }
  667 
  668 /*
  669  * Create a snapshot.
  670  */
  671 static int
  672 fss_create_snapshot(struct fss_softc *sc, struct fss_set *fss, struct lwp *l)
  673 {
  674         int len, error;
  675         u_int32_t csize;
  676         off_t bsize;
  677 
  678         bsize = 0;      /* XXX gcc */
  679 
  680         /*
  681          * Open needed files.
  682          */
  683         if ((error = fss_create_files(sc, fss, &bsize, l)) != 0)
  684                 goto bad;
  685 
  686         if (sc->sc_flags & FSS_PERSISTENT) {
  687                 fss_softc_alloc(sc);
  688                 sc->sc_flags |= FSS_ACTIVE;
  689                 return 0;
  690         }
  691 
  692         /*
  693          * Set cluster size. Must be a power of two and
  694          * a multiple of backing store block size.
  695          */
  696         if (fss->fss_csize <= 0)
  697                 csize = MAXPHYS;
  698         else
  699                 csize = fss->fss_csize;
  700         if (bsize/csize > FSS_CLUSTER_MAX)
  701                 csize = bsize/FSS_CLUSTER_MAX+1;
  702 
  703         for (sc->sc_clshift = sc->sc_bs_bshift; sc->sc_clshift < 32;
  704             sc->sc_clshift++)
  705                 if (FSS_CLSIZE(sc) >= csize)
  706                         break;
  707         if (sc->sc_clshift >= 32) {
  708                 error = EINVAL;
  709                 goto bad;
  710         }
  711         sc->sc_clmask = FSS_CLSIZE(sc)-1;
  712 
  713         /*
  714          * Set number of cache slots.
  715          */
  716         if (FSS_CLSIZE(sc) <= 8192)
  717                 sc->sc_cache_size = 32;
  718         else if (FSS_CLSIZE(sc) <= 65536)
  719                 sc->sc_cache_size = 8;
  720         else
  721                 sc->sc_cache_size = 4;
  722 
  723         /*
  724          * Set number of clusters and size of last cluster.
  725          */
  726         sc->sc_clcount = FSS_BTOCL(sc, bsize-1)+1;
  727         sc->sc_clresid = FSS_CLOFF(sc, bsize-1)+1;
  728 
  729         /*
  730          * Set size of indirect table.
  731          */
  732         len = sc->sc_clcount*sizeof(u_int32_t);
  733         sc->sc_indir_size = FSS_BTOCL(sc, len)+1;
  734         sc->sc_clnext = sc->sc_indir_size;
  735         sc->sc_indir_cur = 0;
  736 
  737         if ((error = fss_softc_alloc(sc)) != 0)
  738                 goto bad;
  739 
  740         /*
  741          * Activate the snapshot.
  742          */
  743 
  744         if ((error = vfs_write_suspend(sc->sc_mount, PUSER|PCATCH, 0)) != 0)
  745                 goto bad;
  746 
  747         microtime(&sc->sc_time);
  748 
  749         if (error == 0)
  750                 error = vn_cow_establish(sc->sc_mount_vp,
  751                     fss_copy_on_write, sc);
  752         if (error == 0)
  753                 sc->sc_flags |= FSS_ACTIVE;
  754 
  755         vfs_write_resume(sc->sc_mount);
  756 
  757         if (error != 0)
  758                 goto bad;
  759 
  760 #ifdef DEBUG
  761         printf("fss%d: %s snapshot active\n", sc->sc_unit, sc->sc_mntname);
  762         printf("fss%d: %u clusters of %u, %u cache slots, %u indir clusters\n",
  763             sc->sc_unit, sc->sc_clcount, FSS_CLSIZE(sc),
  764             sc->sc_cache_size, sc->sc_indir_size);
  765 #endif
  766 
  767         return 0;
  768 
  769 bad:
  770         fss_softc_free(sc);
  771         if (sc->sc_bs_vp != NULL) {
  772                 if (sc->sc_flags & FSS_PERSISTENT)
  773                         vn_close(sc->sc_bs_vp, FREAD, l->l_cred, l);
  774                 else
  775                         vn_close(sc->sc_bs_vp, FREAD|FWRITE, l->l_cred, l);
  776         }
  777         sc->sc_bs_vp = NULL;
  778 
  779         return error;
  780 }
  781 
  782 /*
  783  * Delete a snapshot.
  784  */
  785 static int
  786 fss_delete_snapshot(struct fss_softc *sc, struct lwp *l)
  787 {
  788         int s;
  789 
  790         if ((sc->sc_flags & FSS_PERSISTENT) == 0)
  791                 vn_cow_disestablish(sc->sc_mount_vp, fss_copy_on_write, sc);
  792 
  793         FSS_LOCK(sc, s);
  794         sc->sc_flags &= ~(FSS_ACTIVE|FSS_ERROR);
  795         sc->sc_mount = NULL;
  796         sc->sc_bdev = NODEV;
  797         FSS_UNLOCK(sc, s);
  798 
  799         fss_softc_free(sc);
  800         if (sc->sc_flags & FSS_PERSISTENT)
  801                 vn_close(sc->sc_bs_vp, FREAD, l->l_cred, l);
  802         else
  803                 vn_close(sc->sc_bs_vp, FREAD|FWRITE, l->l_cred, l);
  804         sc->sc_bs_vp = NULL;
  805         sc->sc_flags &= ~FSS_PERSISTENT;
  806 
  807         FSS_STAT_CLEAR(sc);
  808 
  809         return 0;
  810 }
  811 
  812 /*
  813  * A read from the snapshotted block device has completed.
  814  */
  815 static void
  816 fss_cluster_iodone(struct buf *bp)
  817 {
  818         int s;
  819         struct fss_cache *scp = bp->b_private;
  820 
  821         KASSERT(bp->b_vp == NULL);
  822 
  823         FSS_LOCK(scp->fc_softc, s);
  824 
  825         if (bp->b_flags & B_ERROR)
  826                 fss_error(scp->fc_softc, "fs read error %d", bp->b_error);
  827 
  828         if (--scp->fc_xfercount == 0)
  829                 wakeup(&scp->fc_data);
  830 
  831         FSS_UNLOCK(scp->fc_softc, s);
  832 
  833         putiobuf(bp);
  834 }
  835 
  836 /*
  837  * Read a cluster from the snapshotted block device to the cache.
  838  */
  839 static void
  840 fss_read_cluster(struct fss_softc *sc, u_int32_t cl)
  841 {
  842         int s, todo, len;
  843         caddr_t addr;
  844         daddr_t dblk;
  845         struct buf *bp;
  846         struct fss_cache *scp, *scl;
  847 
  848         /*
  849          * Get a free cache slot.
  850          */
  851         scl = sc->sc_cache+sc->sc_cache_size;
  852 
  853         FSS_LOCK(sc, s);
  854 
  855 restart:
  856         if (isset(sc->sc_copied, cl) || !FSS_ISVALID(sc)) {
  857                 FSS_UNLOCK(sc, s);
  858                 return;
  859         }
  860 
  861         for (scp = sc->sc_cache; scp < scl; scp++)
  862                 if (scp->fc_type != FSS_CACHE_FREE &&
  863                     scp->fc_cluster == cl) {
  864                         ltsleep(&scp->fc_type, PRIBIO, "cowwait2", 0,
  865                             &sc->sc_slock);
  866                         goto restart;
  867                 }
  868 
  869         for (scp = sc->sc_cache; scp < scl; scp++)
  870                 if (scp->fc_type == FSS_CACHE_FREE) {
  871                         scp->fc_type = FSS_CACHE_BUSY;
  872                         scp->fc_cluster = cl;
  873                         break;
  874                 }
  875         if (scp >= scl) {
  876                 FSS_STAT_INC(sc, cow_cache_full);
  877                 ltsleep(&sc->sc_cache, PRIBIO, "cowwait3", 0, &sc->sc_slock);
  878                 goto restart;
  879         }
  880 
  881         FSS_UNLOCK(sc, s);
  882 
  883         /*
  884          * Start the read.
  885          */
  886         FSS_STAT_INC(sc, cow_copied);
  887 
  888         dblk = btodb(FSS_CLTOB(sc, cl));
  889         addr = scp->fc_data;
  890         if (cl == sc->sc_clcount-1) {
  891                 todo = sc->sc_clresid;
  892                 memset(addr+todo, 0, FSS_CLSIZE(sc)-todo);
  893         } else
  894                 todo = FSS_CLSIZE(sc);
  895         while (todo > 0) {
  896                 len = todo;
  897                 if (len > MAXPHYS)
  898                         len = MAXPHYS;
  899 
  900                 bp = getiobuf();
  901                 bp->b_flags = B_READ|B_CALL;
  902                 bp->b_bcount = len;
  903                 bp->b_bufsize = bp->b_bcount;
  904                 bp->b_error = 0;
  905                 bp->b_data = addr;
  906                 bp->b_blkno = dblk;
  907                 bp->b_proc = NULL;
  908                 bp->b_dev = sc->sc_bdev;
  909                 bp->b_vp = NULLVP;
  910                 bp->b_private = scp;
  911                 bp->b_iodone = fss_cluster_iodone;
  912 
  913                 DEV_STRATEGY(bp);
  914 
  915                 FSS_LOCK(sc, s);
  916                 scp->fc_xfercount++;
  917                 FSS_UNLOCK(sc, s);
  918 
  919                 dblk += btodb(len);
  920                 addr += len;
  921                 todo -= len;
  922         }
  923 
  924         /*
  925          * Wait for all read requests to complete.
  926          */
  927         FSS_LOCK(sc, s);
  928         while (scp->fc_xfercount > 0)
  929                 ltsleep(&scp->fc_data, PRIBIO, "cowwait", 0, &sc->sc_slock);
  930 
  931         scp->fc_type = FSS_CACHE_VALID;
  932         setbit(sc->sc_copied, scp->fc_cluster);
  933         FSS_UNLOCK(sc, s);
  934 
  935         wakeup(&sc->sc_bs_proc);
  936 }
  937 
  938 /*
  939  * Read/write clusters from/to backing store.
  940  * For persistent snapshots must be called with cl == 0. off is the
  941  * offset into the snapshot.
  942  */
  943 static int
  944 fss_bs_io(struct fss_softc *sc, fss_io_type rw,
  945     u_int32_t cl, off_t off, int len, caddr_t data)
  946 {
  947         int error;
  948 
  949         off += FSS_CLTOB(sc, cl);
  950 
  951         vn_lock(sc->sc_bs_vp, LK_EXCLUSIVE|LK_RETRY);
  952 
  953         error = vn_rdwr((rw == FSS_READ ? UIO_READ : UIO_WRITE), sc->sc_bs_vp,
  954             data, len, off, UIO_SYSSPACE, IO_UNIT|IO_NODELOCKED,
  955             sc->sc_bs_proc->p_cred, NULL, NULL);
  956         if (error == 0) {
  957                 simple_lock(&sc->sc_bs_vp->v_interlock);
  958                 error = VOP_PUTPAGES(sc->sc_bs_vp, trunc_page(off),
  959                     round_page(off+len), PGO_CLEANIT|PGO_SYNCIO|PGO_FREE);
  960         }
  961 
  962         VOP_UNLOCK(sc->sc_bs_vp, 0);
  963 
  964         return error;
  965 }
  966 
  967 /*
  968  * Get a pointer to the indirect slot for this cluster.
  969  */
  970 static u_int32_t *
  971 fss_bs_indir(struct fss_softc *sc, u_int32_t cl)
  972 {
  973         u_int32_t icl;
  974         int ioff;
  975 
  976         icl = cl/(FSS_CLSIZE(sc)/sizeof(u_int32_t));
  977         ioff = cl%(FSS_CLSIZE(sc)/sizeof(u_int32_t));
  978 
  979         if (sc->sc_indir_cur == icl)
  980                 return &sc->sc_indir_data[ioff];
  981 
  982         if (sc->sc_indir_dirty) {
  983                 FSS_STAT_INC(sc, indir_write);
  984                 if (fss_bs_io(sc, FSS_WRITE, sc->sc_indir_cur, 0,
  985                     FSS_CLSIZE(sc), (caddr_t)sc->sc_indir_data) != 0)
  986                         return NULL;
  987                 setbit(sc->sc_indir_valid, sc->sc_indir_cur);
  988         }
  989 
  990         sc->sc_indir_dirty = 0;
  991         sc->sc_indir_cur = icl;
  992 
  993         if (isset(sc->sc_indir_valid, sc->sc_indir_cur)) {
  994                 FSS_STAT_INC(sc, indir_read);
  995                 if (fss_bs_io(sc, FSS_READ, sc->sc_indir_cur, 0,
  996                     FSS_CLSIZE(sc), (caddr_t)sc->sc_indir_data) != 0)
  997                         return NULL;
  998         } else
  999                 memset(sc->sc_indir_data, 0, FSS_CLSIZE(sc));
 1000 
 1001         return &sc->sc_indir_data[ioff];
 1002 }
 1003 
 1004 /*
 1005  * The kernel thread (one for every active snapshot).
 1006  *
 1007  * After wakeup it cleans the cache and runs the I/O requests.
 1008  */
 1009 static void
 1010 fss_bs_thread(void *arg)
 1011 {
 1012         int error, len, nfreed, nio, s;
 1013         long off;
 1014         caddr_t addr;
 1015         u_int32_t c, cl, ch, *indirp;
 1016         struct buf *bp, *nbp;
 1017         struct fss_softc *sc;
 1018         struct fss_cache *scp, *scl;
 1019 
 1020         sc = arg;
 1021 
 1022         scl = sc->sc_cache+sc->sc_cache_size;
 1023 
 1024         nbp = getiobuf();
 1025 
 1026         nfreed = nio = 1;               /* Dont sleep the first time */
 1027 
 1028         FSS_LOCK(sc, s);
 1029 
 1030         for (;;) {
 1031                 if (nfreed == 0 && nio == 0)
 1032                         ltsleep(&sc->sc_bs_proc, PVM-1, "fssbs", 0,
 1033                             &sc->sc_slock);
 1034 
 1035                 if ((sc->sc_flags & FSS_BS_THREAD) == 0) {
 1036                         sc->sc_bs_proc = NULL;
 1037                         wakeup(&sc->sc_bs_proc);
 1038 
 1039                         FSS_UNLOCK(sc, s);
 1040 
 1041                         putiobuf(nbp);
 1042 #ifdef FSS_STATISTICS
 1043                         if ((sc->sc_flags & FSS_PERSISTENT) == 0) {
 1044                                 printf("fss%d: cow called %" PRId64 " times,"
 1045                                     " copied %" PRId64 " clusters,"
 1046                                     " cache full %" PRId64 " times\n",
 1047                                     sc->sc_unit,
 1048                                     FSS_STAT_VAL(sc, cow_calls),
 1049                                     FSS_STAT_VAL(sc, cow_copied),
 1050                                     FSS_STAT_VAL(sc, cow_cache_full));
 1051                                 printf("fss%d: %" PRId64 " indir reads,"
 1052                                     " %" PRId64 " indir writes\n",
 1053                                     sc->sc_unit,
 1054                                     FSS_STAT_VAL(sc, indir_read),
 1055                                     FSS_STAT_VAL(sc, indir_write));
 1056                         }
 1057 #endif /* FSS_STATISTICS */
 1058                         kthread_exit(0);
 1059                 }
 1060 
 1061                 /*
 1062                  * Process I/O requests (persistent)
 1063                  */
 1064 
 1065                 if (sc->sc_flags & FSS_PERSISTENT) {
 1066                         nfreed = nio = 0;
 1067 
 1068                         if ((bp = BUFQ_GET(sc->sc_bufq)) == NULL)
 1069                                 continue;
 1070 
 1071                         nio++;
 1072 
 1073                         if (FSS_ISVALID(sc)) {
 1074                                 FSS_UNLOCK(sc, s);
 1075 
 1076                                 error = fss_bs_io(sc, FSS_READ, 0,
 1077                                     dbtob(bp->b_blkno), bp->b_bcount,
 1078                                     bp->b_data);
 1079 
 1080                                 FSS_LOCK(sc, s);
 1081                         } else
 1082                                 error = ENXIO;
 1083 
 1084                         if (error) {
 1085                                 bp->b_error = error;
 1086                                 bp->b_flags |= B_ERROR;
 1087                                 bp->b_resid = bp->b_bcount;
 1088                         } else
 1089                                 bp->b_resid = 0;
 1090 
 1091                         biodone(bp);
 1092 
 1093                         continue;
 1094                 }
 1095 
 1096                 /*
 1097                  * Clean the cache
 1098                  */
 1099                 nfreed = 0;
 1100                 for (scp = sc->sc_cache; scp < scl; scp++) {
 1101                         if (scp->fc_type != FSS_CACHE_VALID)
 1102                                 continue;
 1103 
 1104                         FSS_UNLOCK(sc, s);
 1105 
 1106                         indirp = fss_bs_indir(sc, scp->fc_cluster);
 1107                         if (indirp != NULL) {
 1108                                 error = fss_bs_io(sc, FSS_WRITE, sc->sc_clnext,
 1109                                     0, FSS_CLSIZE(sc), scp->fc_data);
 1110                         } else
 1111                                 error = EIO;
 1112 
 1113                         FSS_LOCK(sc, s);
 1114 
 1115                         if (error == 0) {
 1116                                 *indirp = sc->sc_clnext++;
 1117                                 sc->sc_indir_dirty = 1;
 1118                         } else
 1119                                 fss_error(sc, "write bs error %d", error);
 1120 
 1121                         scp->fc_type = FSS_CACHE_FREE;
 1122                         nfreed++;
 1123                         wakeup(&scp->fc_type);
 1124                 }
 1125 
 1126                 if (nfreed)
 1127                         wakeup(&sc->sc_cache);
 1128 
 1129                 /*
 1130                  * Process I/O requests
 1131                  */
 1132                 nio = 0;
 1133 
 1134                 if ((bp = BUFQ_GET(sc->sc_bufq)) == NULL)
 1135                         continue;
 1136 
 1137                 nio++;
 1138 
 1139                 if (!FSS_ISVALID(sc)) {
 1140                         bp->b_error = ENXIO;
 1141                         bp->b_flags |= B_ERROR;
 1142                         bp->b_resid = bp->b_bcount;
 1143                         biodone(bp);
 1144                         continue;
 1145                 }
 1146 
 1147                 /*
 1148                  * First read from the snapshotted block device.
 1149                  * XXX Split to only read those parts that have not
 1150                  * been saved to backing store?
 1151                  */
 1152 
 1153                 FSS_UNLOCK(sc, s);
 1154 
 1155                 BUF_INIT(nbp);
 1156                 nbp->b_flags = B_READ;
 1157                 nbp->b_bcount = bp->b_bcount;
 1158                 nbp->b_bufsize = bp->b_bcount;
 1159                 nbp->b_error = 0;
 1160                 nbp->b_data = bp->b_data;
 1161                 nbp->b_blkno = bp->b_blkno;
 1162                 nbp->b_proc = bp->b_proc;
 1163                 nbp->b_dev = sc->sc_bdev;
 1164                 nbp->b_vp = NULLVP;
 1165 
 1166                 DEV_STRATEGY(nbp);
 1167 
 1168                 if (biowait(nbp) != 0) {
 1169                         bp->b_resid = bp->b_bcount;
 1170                         bp->b_error = nbp->b_error;
 1171                         bp->b_flags |= B_ERROR;
 1172                         biodone(bp);
 1173                         FSS_LOCK(sc, s);
 1174                         continue;
 1175                 }
 1176 
 1177                 cl = FSS_BTOCL(sc, dbtob(bp->b_blkno));
 1178                 off = FSS_CLOFF(sc, dbtob(bp->b_blkno));
 1179                 ch = FSS_BTOCL(sc, dbtob(bp->b_blkno)+bp->b_bcount-1);
 1180                 bp->b_resid = bp->b_bcount;
 1181                 addr = bp->b_data;
 1182 
 1183                 FSS_LOCK(sc, s);
 1184 
 1185                 /*
 1186                  * Replace those parts that have been saved to backing store.
 1187                  */
 1188 
 1189                 for (c = cl; c <= ch;
 1190                     c++, off = 0, bp->b_resid -= len, addr += len) {
 1191                         len = FSS_CLSIZE(sc)-off;
 1192                         if (len > bp->b_resid)
 1193                                 len = bp->b_resid;
 1194 
 1195                         if (isclr(sc->sc_copied, c))
 1196                                 continue;
 1197 
 1198                         FSS_UNLOCK(sc, s);
 1199 
 1200                         indirp = fss_bs_indir(sc, c);
 1201 
 1202                         FSS_LOCK(sc, s);
 1203 
 1204                         if (indirp == NULL || *indirp == 0) {
 1205                                 /*
 1206                                  * Not on backing store. Either in cache
 1207                                  * or hole in the snapshotted block device.
 1208                                  */
 1209                                 for (scp = sc->sc_cache; scp < scl; scp++)
 1210                                         if (scp->fc_type == FSS_CACHE_VALID &&
 1211                                             scp->fc_cluster == c)
 1212                                                 break;
 1213                                 if (scp < scl)
 1214                                         memcpy(addr, scp->fc_data+off, len);
 1215                                 else
 1216                                         memset(addr, 0, len);
 1217                                 continue;
 1218                         }
 1219                         /*
 1220                          * Read from backing store.
 1221                          */
 1222 
 1223                         FSS_UNLOCK(sc, s);
 1224 
 1225                         if ((error = fss_bs_io(sc, FSS_READ, *indirp,
 1226                             off, len, addr)) != 0) {
 1227                                 bp->b_resid = bp->b_bcount;
 1228                                 bp->b_error = error;
 1229                                 bp->b_flags |= B_ERROR;
 1230                                 FSS_LOCK(sc, s);
 1231                                 break;
 1232                         }
 1233 
 1234                         FSS_LOCK(sc, s);
 1235 
 1236                 }
 1237 
 1238                 biodone(bp);
 1239         }
 1240 }

Cache object: 8e268facc0728614b58e015456ad0dbe


[ 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.