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

Cache object: 1214adc25ab13c653de5151ecfeb9132


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