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/fs/nandfs/nandfs_cpfile.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 /*-
    2  * Copyright (c) 2010-2012 Semihalf.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/conf.h>
   33 #include <sys/kernel.h>
   34 #include <sys/lock.h>
   35 #include <sys/malloc.h>
   36 #include <sys/mount.h>
   37 #include <sys/mutex.h>
   38 #include <sys/namei.h>
   39 #include <sys/sysctl.h>
   40 #include <sys/vnode.h>
   41 #include <sys/buf.h>
   42 #include <sys/bio.h>
   43 
   44 #include <vm/vm.h>
   45 #include <vm/vm_param.h>
   46 #include <vm/vm_kern.h>
   47 #include <vm/vm_page.h>
   48 
   49 #include "nandfs_mount.h"
   50 #include "nandfs.h"
   51 #include "nandfs_subr.h"
   52 
   53 
   54 static int
   55 nandfs_checkpoint_size(struct nandfs_device *fsdev)
   56 {
   57 
   58         return (fsdev->nd_fsdata.f_checkpoint_size);
   59 }
   60 
   61 static int
   62 nandfs_checkpoint_blk_offset(struct nandfs_device *fsdev, uint64_t cn,
   63     uint64_t *blk, uint64_t *offset)
   64 {
   65         uint64_t off;
   66         uint16_t cp_size, cp_per_blk;
   67 
   68         KASSERT((cn), ("checkpoing cannot be zero"));
   69 
   70         cp_size = fsdev->nd_fsdata.f_checkpoint_size;
   71         cp_per_blk = fsdev->nd_blocksize / cp_size;
   72         off = roundup(sizeof(struct nandfs_cpfile_header), cp_size) / cp_size;
   73         off += (cn - 1);
   74 
   75         *blk = off / cp_per_blk;
   76         *offset = (off % cp_per_blk) * cp_size;
   77 
   78         return (0);
   79 }
   80 
   81 static int
   82 nandfs_checkpoint_blk_remaining(struct nandfs_device *fsdev, uint64_t cn,
   83     uint64_t blk, uint64_t offset)
   84 {
   85         uint16_t cp_size, cp_remaining;
   86 
   87         cp_size = fsdev->nd_fsdata.f_checkpoint_size;
   88         cp_remaining = (fsdev->nd_blocksize - offset) / cp_size;
   89 
   90         return (cp_remaining);
   91 }
   92 
   93 int
   94 nandfs_get_checkpoint(struct nandfs_device *fsdev, struct nandfs_node *cp_node,
   95     uint64_t cn)
   96 {
   97         struct buf *bp;
   98         uint64_t blk, offset;
   99         int error;
  100 
  101         if (cn != fsdev->nd_last_cno && cn != (fsdev->nd_last_cno + 1)) {
  102                 return (-1);
  103         }
  104 
  105         error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
  106         if (error) {
  107                 brelse(bp);
  108                 return (-1);
  109         }
  110 
  111         error = nandfs_dirty_buf(bp, 0);
  112         if (error)
  113                 return (-1);
  114 
  115 
  116         nandfs_checkpoint_blk_offset(fsdev, cn, &blk, &offset);
  117 
  118         if (blk != 0) {
  119                 if (blk < cp_node->nn_inode.i_blocks)
  120                         error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
  121                 else
  122                         error = nandfs_bcreate(cp_node, blk, NOCRED, 0, &bp);
  123                 if (error) {
  124                         if (bp)
  125                                 brelse(bp);
  126                         return (-1);
  127                 }
  128 
  129                 nandfs_dirty_buf(bp, 1);
  130         }
  131 
  132         DPRINTF(CPFILE, ("%s: cn:%#jx entry block:%#jx offset:%#jx\n",
  133             __func__, (uintmax_t)cn, (uintmax_t)blk, (uintmax_t)offset));
  134 
  135         return (0);
  136 }
  137 
  138 int
  139 nandfs_set_checkpoint(struct nandfs_device *fsdev, struct nandfs_node *cp_node,
  140     uint64_t cn, struct nandfs_inode *ifile_inode, uint64_t nblocks)
  141 {
  142         struct nandfs_cpfile_header *cnh;
  143         struct nandfs_checkpoint *cnp;
  144         struct buf *bp;
  145         uint64_t blk, offset;
  146         int error;
  147 
  148         if (cn != fsdev->nd_last_cno && cn != (fsdev->nd_last_cno + 1)) {
  149                 nandfs_error("%s: trying to set invalid chekpoint %jx - %jx\n",
  150                     __func__, cn, fsdev->nd_last_cno);
  151                 return (-1);
  152         }
  153 
  154         error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
  155         if (error) {
  156                 brelse(bp);
  157                 return error;
  158         }
  159 
  160         cnh = (struct nandfs_cpfile_header *) bp->b_data;
  161         cnh->ch_ncheckpoints++;
  162 
  163         nandfs_checkpoint_blk_offset(fsdev, cn, &blk, &offset);
  164 
  165         if(blk != 0) {
  166                 brelse(bp);
  167                 error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
  168                 if (error) {
  169                         brelse(bp);
  170                         return error;
  171                 }
  172         }
  173 
  174         cnp = (struct nandfs_checkpoint *)((uint8_t *)bp->b_data + offset);
  175         cnp->cp_flags = 0;
  176         cnp->cp_checkpoints_count = 1;
  177         memset(&cnp->cp_snapshot_list, 0, sizeof(struct nandfs_snapshot_list));
  178         cnp->cp_cno = cn;
  179         cnp->cp_create = fsdev->nd_ts.tv_sec;
  180         cnp->cp_nblk_inc = nblocks;
  181         cnp->cp_blocks_count = 0;
  182         memcpy (&cnp->cp_ifile_inode, ifile_inode, sizeof(cnp->cp_ifile_inode));
  183 
  184         DPRINTF(CPFILE, ("%s: cn:%#jx ctime:%#jx nblk:%#jx\n",
  185             __func__, (uintmax_t)cn, (uintmax_t)cnp->cp_create,
  186             (uintmax_t)nblocks));
  187 
  188         brelse(bp);
  189         return (0);
  190 }
  191 
  192 static int
  193 nandfs_cp_mounted(struct nandfs_device *nandfsdev, uint64_t cno)
  194 {
  195         struct nandfsmount *nmp;
  196         int mounted = 0;
  197 
  198         mtx_lock(&nandfsdev->nd_mutex);
  199         /* No double-mounting of the same checkpoint */
  200         STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) {
  201                 if (nmp->nm_mount_args.cpno == cno) {
  202                         mounted = 1;
  203                         break;
  204                 }
  205         }
  206         mtx_unlock(&nandfsdev->nd_mutex);
  207 
  208         return (mounted);
  209 }
  210 
  211 static int
  212 nandfs_cp_set_snapshot(struct nandfs_node *cp_node, uint64_t cno)
  213 {
  214         struct nandfs_device *fsdev;
  215         struct nandfs_cpfile_header *cnh;
  216         struct nandfs_checkpoint *cnp;
  217         struct nandfs_snapshot_list *list;
  218         struct buf *bp;
  219         uint64_t blk, prev_blk, offset;
  220         uint64_t curr, prev;
  221         int error;
  222 
  223         fsdev = cp_node->nn_nandfsdev;
  224 
  225         /* Get snapshot data */
  226         nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset);
  227         error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
  228         if (error) {
  229                 brelse(bp);
  230                 return (error);
  231         }
  232         cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
  233         if (cnp->cp_flags & NANDFS_CHECKPOINT_INVALID) {
  234                 brelse(bp);
  235                 return (ENOENT);
  236         }
  237         if ((cnp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT)) {
  238                 brelse(bp);
  239                 return (EINVAL);
  240         }
  241 
  242         brelse(bp);
  243         /* Get list from header */
  244         error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
  245         if (error) {
  246                 brelse(bp);
  247                 return (error);
  248         }
  249 
  250         cnh = (struct nandfs_cpfile_header *) bp->b_data;
  251         list = &cnh->ch_snapshot_list;
  252         prev = list->ssl_prev;
  253         brelse(bp);
  254         prev_blk = ~(0);
  255         curr = 0;
  256         while (prev > cno) {
  257                 curr = prev;
  258                 nandfs_checkpoint_blk_offset(fsdev, prev, &prev_blk, &offset);
  259                 error = nandfs_bread(cp_node, prev_blk, NOCRED, 0, &bp);
  260                 if (error) {
  261                         brelse(bp);
  262                         return (error);
  263                 }
  264                 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
  265                 list = &cnp->cp_snapshot_list;
  266                 prev = list->ssl_prev;
  267                 brelse(bp);
  268         }
  269 
  270         if (curr == 0) {
  271                 nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
  272                 cnh = (struct nandfs_cpfile_header *) bp->b_data;
  273                 list = &cnh->ch_snapshot_list;
  274         } else {
  275                 nandfs_checkpoint_blk_offset(fsdev, curr, &blk, &offset);
  276                 error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
  277                 if (error) {
  278                         brelse(bp);
  279                         return (error);
  280                 }
  281                 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
  282                 list = &cnp->cp_snapshot_list;
  283         }
  284 
  285         list->ssl_prev = cno;
  286         error = nandfs_dirty_buf(bp, 0);
  287         if (error)
  288                 return (error);
  289 
  290 
  291         /* Update snapshot for cno */
  292         nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset);
  293         error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
  294         if (error) {
  295                 brelse(bp);
  296                 return (error);
  297         }
  298         cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
  299         list = &cnp->cp_snapshot_list;
  300         list->ssl_prev = prev;
  301         list->ssl_next = curr;
  302         cnp->cp_flags |= NANDFS_CHECKPOINT_SNAPSHOT;
  303         nandfs_dirty_buf(bp, 1);
  304 
  305         if (prev == 0) {
  306                 nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
  307                 cnh = (struct nandfs_cpfile_header *) bp->b_data;
  308                 list = &cnh->ch_snapshot_list;
  309         } else {
  310                 /* Update snapshot list for prev */
  311                 nandfs_checkpoint_blk_offset(fsdev, prev, &blk, &offset);
  312                 error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
  313                 if (error) {
  314                         brelse(bp);
  315                         return (error);
  316                 }
  317                 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
  318                 list = &cnp->cp_snapshot_list;
  319         }
  320         list->ssl_next = cno;
  321         nandfs_dirty_buf(bp, 1);
  322 
  323         /* Update header */
  324         error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
  325         if (error) {
  326                 brelse(bp);
  327                 return (error);
  328         }
  329         cnh = (struct nandfs_cpfile_header *) bp->b_data;
  330         cnh->ch_nsnapshots++;
  331         nandfs_dirty_buf(bp, 1);
  332 
  333         return (0);
  334 }
  335 
  336 static int
  337 nandfs_cp_clr_snapshot(struct nandfs_node *cp_node, uint64_t cno)
  338 {
  339         struct nandfs_device *fsdev;
  340         struct nandfs_cpfile_header *cnh;
  341         struct nandfs_checkpoint *cnp;
  342         struct nandfs_snapshot_list *list;
  343         struct buf *bp;
  344         uint64_t blk, offset, snapshot_cnt;
  345         uint64_t next, prev;
  346         int error;
  347 
  348         fsdev = cp_node->nn_nandfsdev;
  349 
  350         /* Get snapshot data */
  351         nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset);
  352         error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
  353         if (error) {
  354                 brelse(bp);
  355                 return (error);
  356         }
  357         cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
  358         if (cnp->cp_flags & NANDFS_CHECKPOINT_INVALID) {
  359                 brelse(bp);
  360                 return (ENOENT);
  361         }
  362         if (!(cnp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT)) {
  363                 brelse(bp);
  364                 return (EINVAL);
  365         }
  366 
  367         list = &cnp->cp_snapshot_list;
  368         next = list->ssl_next;
  369         prev = list->ssl_prev;
  370         brelse(bp);
  371 
  372         /* Get previous snapshot */
  373         if (prev != 0) {
  374                 nandfs_checkpoint_blk_offset(fsdev, prev, &blk, &offset);
  375                 error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
  376                 if (error) {
  377                         brelse(bp);
  378                         return (error);
  379                 }
  380                 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
  381                 list = &cnp->cp_snapshot_list;
  382         } else {
  383                 nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
  384                 cnh = (struct nandfs_cpfile_header *) bp->b_data;
  385                 list = &cnh->ch_snapshot_list;
  386         }
  387 
  388         list->ssl_next = next;
  389         error = nandfs_dirty_buf(bp, 0);
  390         if (error)
  391                 return (error);
  392 
  393         /* Get next snapshot */
  394         if (next != 0) {
  395                 nandfs_checkpoint_blk_offset(fsdev, next, &blk, &offset);
  396                 error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
  397                 if (error) {
  398                         brelse(bp);
  399                         return (error);
  400                 }
  401                 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
  402                 list = &cnp->cp_snapshot_list;
  403         } else {
  404                 nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
  405                 cnh = (struct nandfs_cpfile_header *) bp->b_data;
  406                 list = &cnh->ch_snapshot_list;
  407         }
  408         list->ssl_prev = prev;
  409         nandfs_dirty_buf(bp, 1);
  410 
  411         /* Update snapshot list for cno */
  412         nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset);
  413         error = nandfs_bread(cp_node, blk, NOCRED, 0, &bp);
  414         if (error) {
  415                 brelse(bp);
  416                 return (error);
  417         }
  418         cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
  419         list = &cnp->cp_snapshot_list;
  420         list->ssl_prev = 0;
  421         list->ssl_next = 0;
  422         cnp->cp_flags &= !NANDFS_CHECKPOINT_SNAPSHOT;
  423         nandfs_dirty_buf(bp, 1);
  424 
  425         /* Update header */
  426         error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
  427         if (error) {
  428                 brelse(bp);
  429                 return (error);
  430         }
  431         cnh = (struct nandfs_cpfile_header *) bp->b_data;
  432         snapshot_cnt = cnh->ch_nsnapshots;
  433         snapshot_cnt--;
  434         cnh->ch_nsnapshots = snapshot_cnt;
  435         nandfs_dirty_buf(bp, 1);
  436 
  437         return (0);
  438 }
  439 
  440 int
  441 nandfs_chng_cpmode(struct nandfs_node *node, struct nandfs_cpmode *ncpm)
  442 {
  443         struct nandfs_device *fsdev;
  444         uint64_t cno = ncpm->ncpm_cno;
  445         int mode = ncpm->ncpm_mode;
  446         int ret;
  447 
  448         fsdev = node->nn_nandfsdev;
  449         VOP_LOCK(NTOV(node), LK_EXCLUSIVE);
  450         switch (mode) {
  451         case NANDFS_CHECKPOINT:
  452                 if (nandfs_cp_mounted(fsdev, cno)) {
  453                         ret = EBUSY;
  454                 } else
  455                         ret = nandfs_cp_clr_snapshot(node, cno);
  456                 break;
  457         case NANDFS_SNAPSHOT:
  458                 ret = nandfs_cp_set_snapshot(node, cno);
  459                 break;
  460         default:
  461                 ret = EINVAL;
  462                 break;
  463         }
  464         VOP_UNLOCK(NTOV(node), 0);
  465 
  466         return (ret);
  467 }
  468 
  469 static void
  470 nandfs_cpinfo_fill(struct nandfs_checkpoint *cnp, struct nandfs_cpinfo *nci)
  471 {
  472 
  473         nci->nci_flags = cnp->cp_flags;
  474         nci->nci_pad = 0;
  475         nci->nci_cno = cnp->cp_cno;
  476         nci->nci_create = cnp->cp_create;
  477         nci->nci_nblk_inc = cnp->cp_nblk_inc;
  478         nci->nci_blocks_count = cnp->cp_blocks_count;
  479         nci->nci_next = cnp->cp_snapshot_list.ssl_next;
  480         DPRINTF(CPFILE, ("%s: cn:%#jx ctime:%#jx\n",
  481             __func__, (uintmax_t)cnp->cp_cno,
  482             (uintmax_t)cnp->cp_create));
  483 }
  484 
  485 static int
  486 nandfs_get_cpinfo_cp(struct nandfs_node *node, uint64_t cno,
  487     struct nandfs_cpinfo *nci, uint32_t mnmembs, uint32_t *nmembs)
  488 {
  489         struct nandfs_device *fsdev;
  490         struct buf *bp;
  491         uint64_t blk, offset, last_cno, i;
  492         uint16_t remaining;
  493         int error;
  494 #ifdef INVARIANTS
  495         uint64_t testblk, testoffset;
  496 #endif
  497 
  498         if (cno == 0) {
  499                 return (ENOENT);
  500         }
  501 
  502         if (mnmembs < 1) {
  503                 return (EINVAL);
  504         }
  505 
  506         fsdev = node->nn_nandfsdev;
  507         last_cno = fsdev->nd_last_cno;
  508         DPRINTF(CPFILE, ("%s: cno:%#jx mnmembs: %#jx last:%#jx\n", __func__,
  509             (uintmax_t)cno, (uintmax_t)mnmembs,
  510             (uintmax_t)fsdev->nd_last_cno));
  511 
  512         /*
  513          * do {
  514          *      get block
  515          *      read checkpoints until we hit last checkpoint, end of block or
  516          *      requested number
  517          * } while (last read checkpoint <= last checkpoint on fs &&
  518          *              read checkpoints < request number);
  519          */
  520         *nmembs = i = 0;
  521         do {
  522                 nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset);
  523                 remaining = nandfs_checkpoint_blk_remaining(fsdev, cno,
  524                     blk, offset);
  525                 error = nandfs_bread(node, blk, NOCRED, 0, &bp);
  526                 if (error) {
  527                         brelse(bp);
  528                         return (error);
  529                 }
  530 
  531                 while (cno <= last_cno && i < mnmembs && remaining) {
  532 #ifdef INVARIANTS
  533                         nandfs_checkpoint_blk_offset(fsdev, cno, &testblk,
  534                             &testoffset);
  535                         KASSERT(testblk == blk, ("testblk != blk"));
  536                         KASSERT(testoffset == offset, ("testoffset != offset"));
  537 #endif
  538                         DPRINTF(CPFILE, ("%s: cno %#jx\n", __func__,
  539                             (uintmax_t)cno));
  540 
  541                         nandfs_cpinfo_fill((struct nandfs_checkpoint *)
  542                             (bp->b_data + offset), nci);
  543                         offset += nandfs_checkpoint_size(fsdev);
  544                         i++;
  545                         nci++;
  546                         cno++;
  547                         (*nmembs)++;
  548                         remaining--;
  549                 }
  550                 brelse(bp);
  551         } while (cno <= last_cno && i < mnmembs);
  552 
  553         return (0);
  554 }
  555 
  556 static int
  557 nandfs_get_cpinfo_sp(struct nandfs_node *node, uint64_t cno,
  558     struct nandfs_cpinfo *nci, uint32_t mnmembs, uint32_t *nmembs)
  559 {
  560         struct nandfs_checkpoint *cnp;
  561         struct nandfs_cpfile_header *cnh;
  562         struct nandfs_device *fsdev;
  563         struct buf *bp = NULL;
  564         uint64_t curr = 0;
  565         uint64_t blk, offset, curr_cno;
  566         uint32_t flag;
  567         int i, error;
  568 
  569         if (cno == 0 || cno == ~(0))
  570                 return (ENOENT);
  571 
  572         fsdev = node->nn_nandfsdev;
  573         curr_cno = cno;
  574 
  575         if (nmembs)
  576                 *nmembs = 0;
  577         if (curr_cno == 1) {
  578                 /* Get list from header */
  579                 error = nandfs_bread(node, 0, NOCRED, 0, &bp);
  580                 if (error) {
  581                         brelse(bp);
  582                         return (error);
  583                 }
  584                 cnh = (struct nandfs_cpfile_header *) bp->b_data;
  585                 curr_cno = cnh->ch_snapshot_list.ssl_next;
  586                 brelse(bp);
  587                 bp = NULL;
  588 
  589                 /* No snapshots */
  590                 if (curr_cno == 0)
  591                         return (0);
  592         }
  593 
  594         for (i = 0; i < mnmembs; i++, nci++) {
  595                 nandfs_checkpoint_blk_offset(fsdev, curr_cno, &blk, &offset);
  596                 if (i == 0 || curr != blk) {
  597                         if (bp)
  598                                 brelse(bp);
  599                         error = nandfs_bread(node, blk, NOCRED, 0, &bp);
  600                         if (error) {
  601                                 brelse(bp);
  602                                 return (ENOENT);
  603                         }
  604                         curr = blk;
  605                 }
  606                 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
  607                 flag = cnp->cp_flags;
  608                 if (!(flag & NANDFS_CHECKPOINT_SNAPSHOT) ||
  609                     (flag & NANDFS_CHECKPOINT_INVALID))
  610                         break;
  611 
  612                 nci->nci_flags = flag;
  613                 nci->nci_pad = 0;
  614                 nci->nci_cno = cnp->cp_cno;
  615                 nci->nci_create = cnp->cp_create;
  616                 nci->nci_nblk_inc = cnp->cp_nblk_inc;
  617                 nci->nci_blocks_count = cnp->cp_blocks_count;
  618                 nci->nci_next = cnp->cp_snapshot_list.ssl_next;
  619                 if (nmembs)
  620                         (*nmembs)++;
  621 
  622                 curr_cno = nci->nci_next;
  623                 if (!curr_cno)
  624                         break;
  625         }
  626 
  627         brelse(bp);
  628 
  629         return (0);
  630 }
  631 
  632 int
  633 nandfs_get_cpinfo(struct nandfs_node *node, uint64_t cno, uint16_t flags,
  634     struct nandfs_cpinfo *nci, uint32_t nmembs, uint32_t *nnmembs)
  635 {
  636         int error;
  637 
  638         VOP_LOCK(NTOV(node), LK_EXCLUSIVE);
  639         switch (flags) {
  640         case NANDFS_CHECKPOINT:
  641                 error = nandfs_get_cpinfo_cp(node, cno, nci, nmembs, nnmembs);
  642                 break;
  643         case NANDFS_SNAPSHOT:
  644                 error = nandfs_get_cpinfo_sp(node, cno, nci, nmembs, nnmembs);
  645                 break;
  646         default:
  647                 error = EINVAL;
  648                 break;
  649         }
  650         VOP_UNLOCK(NTOV(node), 0);
  651 
  652         return (error);
  653 }
  654 
  655 int
  656 nandfs_get_cpinfo_ioctl(struct nandfs_node *node, struct nandfs_argv *nargv)
  657 {
  658         struct nandfs_cpinfo *nci;
  659         uint64_t cno = nargv->nv_index;
  660         void *buf = (void *)((uintptr_t)nargv->nv_base);
  661         uint16_t flags = nargv->nv_flags;
  662         uint32_t nmembs = 0;
  663         int error;
  664 
  665         if (nargv->nv_nmembs > NANDFS_CPINFO_MAX)
  666                 return (EINVAL);
  667 
  668         nci = malloc(sizeof(struct nandfs_cpinfo) * nargv->nv_nmembs,
  669             M_NANDFSTEMP, M_WAITOK | M_ZERO);
  670 
  671         error = nandfs_get_cpinfo(node, cno, flags, nci, nargv->nv_nmembs, &nmembs);
  672 
  673         if (error == 0) {
  674                 nargv->nv_nmembs = nmembs;
  675                 error = copyout(nci, buf,
  676                     sizeof(struct nandfs_cpinfo) * nmembs);
  677         }
  678 
  679         free(nci, M_NANDFSTEMP);
  680         return (error);
  681 }
  682 
  683 int
  684 nandfs_delete_cp(struct nandfs_node *node, uint64_t start, uint64_t end)
  685 {
  686         struct nandfs_checkpoint *cnp;
  687         struct nandfs_device *fsdev;
  688         struct buf *bp;
  689         uint64_t cno = start, blk, offset;
  690         int error;
  691 
  692         DPRINTF(CPFILE, ("%s: delete cno %jx-%jx\n", __func__, start, end));
  693         VOP_LOCK(NTOV(node), LK_EXCLUSIVE);
  694         fsdev = node->nn_nandfsdev;
  695         for (cno = start; cno <= end; cno++) {
  696                 if (!cno)
  697                         continue;
  698 
  699                 nandfs_checkpoint_blk_offset(fsdev, cno, &blk, &offset);
  700                 error = nandfs_bread(node, blk, NOCRED, 0, &bp);
  701                 if (error) {
  702                         VOP_UNLOCK(NTOV(node), 0);
  703                         brelse(bp);
  704                         return (error);
  705                 }
  706 
  707                 cnp = (struct nandfs_checkpoint *)(bp->b_data + offset);
  708                 if (cnp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT) {
  709                         brelse(bp);
  710                         VOP_UNLOCK(NTOV(node), 0);
  711                         return (0);
  712                 }
  713 
  714                 cnp->cp_flags |= NANDFS_CHECKPOINT_INVALID;
  715 
  716                 error = nandfs_dirty_buf(bp, 0);
  717                 if (error)
  718                         return (error);
  719         }
  720         VOP_UNLOCK(NTOV(node), 0);
  721 
  722         return (0);
  723 }
  724 
  725 int
  726 nandfs_make_snap(struct nandfs_device *fsdev, uint64_t *cno)
  727 {
  728         struct nandfs_cpmode cpm;
  729         int error;
  730 
  731         *cno = cpm.ncpm_cno = fsdev->nd_last_cno;
  732         cpm.ncpm_mode = NANDFS_SNAPSHOT;
  733         error = nandfs_chng_cpmode(fsdev->nd_cp_node, &cpm);
  734         return (error);
  735 }
  736 
  737 int
  738 nandfs_delete_snap(struct nandfs_device *fsdev, uint64_t cno)
  739 {
  740         struct nandfs_cpmode cpm;
  741         int error;
  742 
  743         cpm.ncpm_cno = cno;
  744         cpm.ncpm_mode = NANDFS_CHECKPOINT;
  745         error = nandfs_chng_cpmode(fsdev->nd_cp_node, &cpm);
  746         return (error);
  747 }
  748 
  749 int nandfs_get_cpstat(struct nandfs_node *cp_node, struct nandfs_cpstat *ncp)
  750 {
  751         struct nandfs_device *fsdev;
  752         struct nandfs_cpfile_header *cnh;
  753         struct buf *bp;
  754         int error;
  755 
  756         VOP_LOCK(NTOV(cp_node), LK_EXCLUSIVE);
  757         fsdev = cp_node->nn_nandfsdev;
  758 
  759         /* Get header */
  760         error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp);
  761         if (error) {
  762                 brelse(bp);
  763                 VOP_UNLOCK(NTOV(cp_node), 0);
  764                 return (error);
  765         }
  766         cnh = (struct nandfs_cpfile_header *) bp->b_data;
  767         ncp->ncp_cno = fsdev->nd_last_cno;
  768         ncp->ncp_ncps = cnh->ch_ncheckpoints;
  769         ncp->ncp_nss = cnh->ch_nsnapshots;
  770         DPRINTF(CPFILE, ("%s: cno:%#jx ncps:%#jx nss:%#jx\n",
  771             __func__, ncp->ncp_cno, ncp->ncp_ncps, ncp->ncp_nss));
  772         brelse(bp);
  773         VOP_UNLOCK(NTOV(cp_node), 0);
  774 
  775         return (0);
  776 }

Cache object: f39dc8587804f5b85f9e1eba924f8fac


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