LCOV - code coverage report
Current view: top level - fs/xfs/libxfs - xfs_rtbitmap.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-djwa @ Mon Jul 31 20:08:17 PDT 2023 Lines: 371 390 95.1 %
Date: 2023-07-31 20:08:17 Functions: 15 15 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (c) 2000-2005 Silicon Graphics, Inc.
       4             :  * All Rights Reserved.
       5             :  */
       6             : #include "xfs.h"
       7             : #include "xfs_fs.h"
       8             : #include "xfs_shared.h"
       9             : #include "xfs_format.h"
      10             : #include "xfs_log_format.h"
      11             : #include "xfs_trans_resv.h"
      12             : #include "xfs_bit.h"
      13             : #include "xfs_mount.h"
      14             : #include "xfs_inode.h"
      15             : #include "xfs_bmap.h"
      16             : #include "xfs_trans.h"
      17             : #include "xfs_rtalloc.h"
      18             : #include "xfs_error.h"
      19             : 
      20             : /*
      21             :  * Realtime allocator bitmap functions shared with userspace.
      22             :  */
      23             : 
      24             : /*
      25             :  * Real time buffers need verifiers to avoid runtime warnings during IO.
      26             :  * We don't have anything to verify, however, so these are just dummy
      27             :  * operations.
      28             :  */
      29             : static void
      30       82583 : xfs_rtbuf_verify_read(
      31             :         struct xfs_buf  *bp)
      32             : {
      33       82583 :         return;
      34             : }
      35             : 
      36             : static void
      37      425339 : xfs_rtbuf_verify_write(
      38             :         struct xfs_buf  *bp)
      39             : {
      40      425339 :         return;
      41             : }
      42             : 
      43             : const struct xfs_buf_ops xfs_rtbuf_ops = {
      44             :         .name = "rtbuf",
      45             :         .verify_read = xfs_rtbuf_verify_read,
      46             :         .verify_write = xfs_rtbuf_verify_write,
      47             : };
      48             : 
      49             : /*
      50             :  * Get a buffer for the bitmap or summary file block specified.
      51             :  * The buffer is returned read and locked.
      52             :  */
      53             : int
      54   657583802 : xfs_rtbuf_get(
      55             :         xfs_mount_t     *mp,            /* file system mount structure */
      56             :         xfs_trans_t     *tp,            /* transaction pointer */
      57             :         xfs_rtblock_t   block,          /* block number in bitmap or summary */
      58             :         int             issum,          /* is summary not bitmap */
      59             :         struct xfs_buf  **bpp)          /* output: buffer for the block */
      60             : {
      61   657583802 :         struct xfs_buf  *bp;            /* block buffer, result */
      62   657583802 :         xfs_inode_t     *ip;            /* bitmap or summary inode */
      63   657583802 :         xfs_bmbt_irec_t map;
      64   657583802 :         int             nmap = 1;
      65   657583802 :         int             error;          /* error value */
      66             : 
      67   657583802 :         ip = issum ? mp->m_rsumip : mp->m_rbmip;
      68             : 
      69   657583802 :         error = xfs_bmapi_read(ip, block, 1, &map, &nmap, 0);
      70   657590101 :         if (error)
      71             :                 return error;
      72             : 
      73   657590101 :         if (XFS_IS_CORRUPT(mp, nmap == 0 || !xfs_bmap_is_written_extent(&map)))
      74           0 :                 return -EFSCORRUPTED;
      75             : 
      76   657590101 :         ASSERT(map.br_startblock != NULLFSBLOCK);
      77  1972777307 :         error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
      78   657590101 :                                    XFS_FSB_TO_DADDR(mp, map.br_startblock),
      79             :                                    mp->m_bsize, 0, &bp, &xfs_rtbuf_ops);
      80   657592508 :         if (error)
      81             :                 return error;
      82             : 
      83  1296078959 :         xfs_trans_buf_set_type(tp, bp, issum ? XFS_BLFT_RTSUMMARY_BUF
      84             :                                              : XFS_BLFT_RTBITMAP_BUF);
      85   657595005 :         *bpp = bp;
      86   657595005 :         return 0;
      87             : }
      88             : 
      89             : /*
      90             :  * Searching backward from start to limit, find the first block whose
      91             :  * allocated/free state is different from start's.
      92             :  */
      93             : int
      94     9541577 : xfs_rtfind_back(
      95             :         xfs_mount_t     *mp,            /* file system mount point */
      96             :         xfs_trans_t     *tp,            /* transaction pointer */
      97             :         xfs_rtblock_t   start,          /* starting block to look at */
      98             :         xfs_rtblock_t   limit,          /* last block to look at */
      99             :         xfs_rtblock_t   *rtblock)       /* out: start block found */
     100             : {
     101     9541577 :         xfs_rtword_t    *b;             /* current word in buffer */
     102     9541577 :         int             bit;            /* bit number in the word */
     103     9541577 :         xfs_rtblock_t   block;          /* bitmap block number */
     104     9541577 :         struct xfs_buf  *bp;            /* buf for the block */
     105     9541577 :         xfs_rtword_t    *bufp;          /* starting word in buffer */
     106     9541577 :         int             error;          /* error value */
     107     9541577 :         xfs_rtblock_t   firstbit;       /* first useful bit in the word */
     108     9541577 :         xfs_rtblock_t   i;              /* current bit number rel. to start */
     109     9541577 :         xfs_rtblock_t   len;            /* length of inspected area */
     110     9541577 :         xfs_rtword_t    mask;           /* mask of relevant bits for value */
     111     9541577 :         xfs_rtword_t    want;           /* mask for "good" values */
     112     9541577 :         xfs_rtword_t    wdiff;          /* difference from wanted value */
     113     9541577 :         int             word;           /* word number in the buffer */
     114             : 
     115             :         /*
     116             :          * Compute and read in starting bitmap block for starting block.
     117             :          */
     118     9541577 :         block = XFS_BITTOBLOCK(mp, start);
     119     9541577 :         error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
     120     9541577 :         if (error) {
     121             :                 return error;
     122             :         }
     123     9541577 :         bufp = bp->b_addr;
     124             :         /*
     125             :          * Get the first word's index & point to it.
     126             :          */
     127     9541577 :         word = XFS_BITTOWORD(mp, start);
     128     9541577 :         b = &bufp[word];
     129     9541577 :         bit = (int)(start & (XFS_NBWORD - 1));
     130     9541577 :         len = start - limit + 1;
     131             :         /*
     132             :          * Compute match value, based on the bit at start: if 1 (free)
     133             :          * then all-ones, else all-zeroes.
     134             :          */
     135     9541577 :         want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0;
     136             :         /*
     137             :          * If the starting position is not word-aligned, deal with the
     138             :          * partial word.
     139             :          */
     140     9541577 :         if (bit < XFS_NBWORD - 1) {
     141             :                 /*
     142             :                  * Calculate first (leftmost) bit number to look at,
     143             :                  * and mask for all the relevant bits in this word.
     144             :                  */
     145     9249677 :                 firstbit = XFS_RTMAX((xfs_srtblock_t)(bit - len + 1), 0);
     146     9249677 :                 mask = (((xfs_rtword_t)1 << (bit - firstbit + 1)) - 1) <<
     147             :                         firstbit;
     148             :                 /*
     149             :                  * Calculate the difference between the value there
     150             :                  * and what we're looking for.
     151             :                  */
     152     9249677 :                 if ((wdiff = (*b ^ want) & mask)) {
     153             :                         /*
     154             :                          * Different.  Mark where we are and return.
     155             :                          */
     156     8592158 :                         xfs_trans_brelse(tp, bp);
     157     8592158 :                         i = bit - XFS_RTHIBIT(wdiff);
     158     8592158 :                         *rtblock = start - i + 1;
     159     8592158 :                         return 0;
     160             :                 }
     161      657519 :                 i = bit - firstbit + 1;
     162             :                 /*
     163             :                  * Go on to previous block if that's where the previous word is
     164             :                  * and we need the previous word.
     165             :                  */
     166      657519 :                 if (--word == -1 && i < len) {
     167             :                         /*
     168             :                          * If done with this block, get the previous one.
     169             :                          */
     170        4451 :                         xfs_trans_brelse(tp, bp);
     171        4451 :                         error = xfs_rtbuf_get(mp, tp, --block, 0, &bp);
     172        4451 :                         if (error) {
     173             :                                 return error;
     174             :                         }
     175        4451 :                         bufp = bp->b_addr;
     176        4451 :                         word = XFS_BLOCKWMASK(mp);
     177        4451 :                         b = &bufp[word];
     178             :                 } else {
     179             :                         /*
     180             :                          * Go on to the previous word in the buffer.
     181             :                          */
     182      653068 :                         b--;
     183             :                 }
     184             :         } else {
     185             :                 /*
     186             :                  * Starting on a word boundary, no partial word.
     187             :                  */
     188             :                 i = 0;
     189             :         }
     190             :         /*
     191             :          * Loop over whole words in buffers.  When we use up one buffer
     192             :          * we move on to the previous one.
     193             :          */
     194    46263654 :         while (len - i >= XFS_NBWORD) {
     195             :                 /*
     196             :                  * Compute difference between actual and desired value.
     197             :                  */
     198    46200443 :                 if ((wdiff = *b ^ want)) {
     199             :                         /*
     200             :                          * Different, mark where we are and return.
     201             :                          */
     202      886208 :                         xfs_trans_brelse(tp, bp);
     203      886208 :                         i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff);
     204      886208 :                         *rtblock = start - i + 1;
     205      886208 :                         return 0;
     206             :                 }
     207    45314235 :                 i += XFS_NBWORD;
     208             :                 /*
     209             :                  * Go on to previous block if that's where the previous word is
     210             :                  * and we need the previous word.
     211             :                  */
     212    45314235 :                 if (--word == -1 && i < len) {
     213             :                         /*
     214             :                          * If done with this block, get the previous one.
     215             :                          */
     216       41739 :                         xfs_trans_brelse(tp, bp);
     217       41739 :                         error = xfs_rtbuf_get(mp, tp, --block, 0, &bp);
     218       41739 :                         if (error) {
     219           0 :                                 return error;
     220             :                         }
     221       41739 :                         bufp = bp->b_addr;
     222       41739 :                         word = XFS_BLOCKWMASK(mp);
     223       41739 :                         b = &bufp[word];
     224             :                 } else {
     225             :                         /*
     226             :                          * Go on to the previous word in the buffer.
     227             :                          */
     228    45272496 :                         b--;
     229             :                 }
     230             :         }
     231             :         /*
     232             :          * If not ending on a word boundary, deal with the last
     233             :          * (partial) word.
     234             :          */
     235       63211 :         if (len - i) {
     236             :                 /*
     237             :                  * Calculate first (leftmost) bit number to look at,
     238             :                  * and mask for all the relevant bits in this word.
     239             :                  */
     240           0 :                 firstbit = XFS_NBWORD - (len - i);
     241           0 :                 mask = (((xfs_rtword_t)1 << (len - i)) - 1) << firstbit;
     242             :                 /*
     243             :                  * Compute difference between actual and desired value.
     244             :                  */
     245           0 :                 if ((wdiff = (*b ^ want) & mask)) {
     246             :                         /*
     247             :                          * Different, mark where we are and return.
     248             :                          */
     249           0 :                         xfs_trans_brelse(tp, bp);
     250           0 :                         i += XFS_NBWORD - 1 - XFS_RTHIBIT(wdiff);
     251           0 :                         *rtblock = start - i + 1;
     252           0 :                         return 0;
     253             :                 } else
     254             :                         i = len;
     255             :         }
     256             :         /*
     257             :          * No match, return that we scanned the whole area.
     258             :          */
     259       63211 :         xfs_trans_brelse(tp, bp);
     260       63211 :         *rtblock = start - i + 1;
     261       63211 :         return 0;
     262             : }
     263             : 
     264             : /*
     265             :  * Searching forward from start to limit, find the first block whose
     266             :  * allocated/free state is different from start's.
     267             :  */
     268             : int
     269   131168376 : xfs_rtfind_forw(
     270             :         xfs_mount_t     *mp,            /* file system mount point */
     271             :         xfs_trans_t     *tp,            /* transaction pointer */
     272             :         xfs_rtblock_t   start,          /* starting block to look at */
     273             :         xfs_rtblock_t   limit,          /* last block to look at */
     274             :         xfs_rtblock_t   *rtblock)       /* out: start block found */
     275             : {
     276   131168376 :         xfs_rtword_t    *b;             /* current word in buffer */
     277   131168376 :         int             bit;            /* bit number in the word */
     278   131168376 :         xfs_rtblock_t   block;          /* bitmap block number */
     279   131168376 :         struct xfs_buf  *bp;            /* buf for the block */
     280   131168376 :         xfs_rtword_t    *bufp;          /* starting word in buffer */
     281   131168376 :         int             error;          /* error value */
     282   131168376 :         xfs_rtblock_t   i;              /* current bit number rel. to start */
     283   131168376 :         xfs_rtblock_t   lastbit;        /* last useful bit in the word */
     284   131168376 :         xfs_rtblock_t   len;            /* length of inspected area */
     285   131168376 :         xfs_rtword_t    mask;           /* mask of relevant bits for value */
     286   131168376 :         xfs_rtword_t    want;           /* mask for "good" values */
     287   131168376 :         xfs_rtword_t    wdiff;          /* difference from wanted value */
     288   131168376 :         int             word;           /* word number in the buffer */
     289             : 
     290             :         /*
     291             :          * Compute and read in starting bitmap block for starting block.
     292             :          */
     293   131168376 :         block = XFS_BITTOBLOCK(mp, start);
     294   131168376 :         error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
     295   131168376 :         if (error) {
     296             :                 return error;
     297             :         }
     298   131168376 :         bufp = bp->b_addr;
     299             :         /*
     300             :          * Get the first word's index & point to it.
     301             :          */
     302   131168376 :         word = XFS_BITTOWORD(mp, start);
     303   131168376 :         b = &bufp[word];
     304   131168376 :         bit = (int)(start & (XFS_NBWORD - 1));
     305   131168376 :         len = limit - start + 1;
     306             :         /*
     307             :          * Compute match value, based on the bit at start: if 1 (free)
     308             :          * then all-ones, else all-zeroes.
     309             :          */
     310   131168376 :         want = (*b & ((xfs_rtword_t)1 << bit)) ? -1 : 0;
     311             :         /*
     312             :          * If the starting position is not word-aligned, deal with the
     313             :          * partial word.
     314             :          */
     315   131168376 :         if (bit) {
     316             :                 /*
     317             :                  * Calculate last (rightmost) bit number to look at,
     318             :                  * and mask for all the relevant bits in this word.
     319             :                  */
     320   113541162 :                 lastbit = XFS_RTMIN(bit + len, XFS_NBWORD);
     321   113541162 :                 mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit;
     322             :                 /*
     323             :                  * Calculate the difference between the value there
     324             :                  * and what we're looking for.
     325             :                  */
     326   113541162 :                 if ((wdiff = (*b ^ want) & mask)) {
     327             :                         /*
     328             :                          * Different.  Mark where we are and return.
     329             :                          */
     330    29453392 :                         xfs_trans_brelse(tp, bp);
     331    29453392 :                         i = XFS_RTLOBIT(wdiff) - bit;
     332    29453392 :                         *rtblock = start + i - 1;
     333    29453392 :                         return 0;
     334             :                 }
     335    84087770 :                 i = lastbit - bit;
     336             :                 /*
     337             :                  * Go on to next block if that's where the next word is
     338             :                  * and we need the next word.
     339             :                  */
     340    84087770 :                 if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
     341             :                         /*
     342             :                          * If done with this block, get the previous one.
     343             :                          */
     344      304436 :                         xfs_trans_brelse(tp, bp);
     345      304436 :                         error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
     346      304436 :                         if (error) {
     347             :                                 return error;
     348             :                         }
     349      304436 :                         b = bufp = bp->b_addr;
     350      304436 :                         word = 0;
     351             :                 } else {
     352             :                         /*
     353             :                          * Go on to the previous word in the buffer.
     354             :                          */
     355    83783334 :                         b++;
     356             :                 }
     357             :         } else {
     358             :                 /*
     359             :                  * Starting on a word boundary, no partial word.
     360             :                  */
     361             :                 i = 0;
     362             :         }
     363             :         /*
     364             :          * Loop over whole words in buffers.  When we use up one buffer
     365             :          * we move on to the next one.
     366             :          */
     367 >20427*10^7 :         while (len - i >= XFS_NBWORD) {
     368             :                 /*
     369             :                  * Compute difference between actual and desired value.
     370             :                  */
     371 >20426*10^7 :                 if ((wdiff = *b ^ want)) {
     372             :                         /*
     373             :                          * Different, mark where we are and return.
     374             :                          */
     375    93754327 :                         xfs_trans_brelse(tp, bp);
     376    93754327 :                         i += XFS_RTLOBIT(wdiff);
     377    93754327 :                         *rtblock = start + i - 1;
     378    93754327 :                         return 0;
     379             :                 }
     380 >20416*10^7 :                 i += XFS_NBWORD;
     381             :                 /*
     382             :                  * Go on to next block if that's where the next word is
     383             :                  * and we need the next word.
     384             :                  */
     385 >20416*10^7 :                 if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
     386             :                         /*
     387             :                          * If done with this block, get the next one.
     388             :                          */
     389   189126385 :                         xfs_trans_brelse(tp, bp);
     390   189126385 :                         error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
     391   189126385 :                         if (error) {
     392           0 :                                 return error;
     393             :                         }
     394   189126385 :                         b = bufp = bp->b_addr;
     395   189126385 :                         word = 0;
     396             :                 } else {
     397             :                         /*
     398             :                          * Go on to the next word in the buffer.
     399             :                          */
     400 >20397*10^7 :                         b++;
     401             :                 }
     402             :         }
     403             :         /*
     404             :          * If not ending on a word boundary, deal with the last
     405             :          * (partial) word.
     406             :          */
     407     7960657 :         if ((lastbit = len - i)) {
     408             :                 /*
     409             :                  * Calculate mask for all the relevant bits in this word.
     410             :                  */
     411           0 :                 mask = ((xfs_rtword_t)1 << lastbit) - 1;
     412             :                 /*
     413             :                  * Compute difference between actual and desired value.
     414             :                  */
     415           0 :                 if ((wdiff = (*b ^ want) & mask)) {
     416             :                         /*
     417             :                          * Different, mark where we are and return.
     418             :                          */
     419           0 :                         xfs_trans_brelse(tp, bp);
     420           0 :                         i += XFS_RTLOBIT(wdiff);
     421           0 :                         *rtblock = start + i - 1;
     422           0 :                         return 0;
     423             :                 } else
     424             :                         i = len;
     425             :         }
     426             :         /*
     427             :          * No match, return that we scanned the whole area.
     428             :          */
     429     7960657 :         xfs_trans_brelse(tp, bp);
     430     7960657 :         *rtblock = start + i - 1;
     431     7960657 :         return 0;
     432             : }
     433             : 
     434             : /*
     435             :  * Read and/or modify the summary information for a given extent size,
     436             :  * bitmap block combination.
     437             :  * Keeps track of a current summary block, so we don't keep reading
     438             :  * it from the buffer cache.
     439             :  *
     440             :  * Summary information is returned in *sum if specified.
     441             :  * If no delta is specified, returns summary only.
     442             :  */
     443             : int
     444   116500788 : xfs_rtmodify_summary_int(
     445             :         xfs_mount_t     *mp,            /* file system mount structure */
     446             :         xfs_trans_t     *tp,            /* transaction pointer */
     447             :         int             log,            /* log2 of extent size */
     448             :         xfs_rtblock_t   bbno,           /* bitmap block number */
     449             :         int             delta,          /* change to make to summary info */
     450             :         struct xfs_buf  **rbpp,         /* in/out: summary block buffer */
     451             :         xfs_fsblock_t   *rsb,           /* in/out: summary block number */
     452             :         xfs_suminfo_t   *sum)           /* out: summary info for this block */
     453             : {
     454   116500788 :         struct xfs_buf  *bp;            /* buffer for the summary block */
     455   116500788 :         int             error;          /* error value */
     456   116500788 :         xfs_fsblock_t   sb;             /* summary fsblock */
     457   116500788 :         int             so;             /* index into the summary file */
     458   116500788 :         xfs_suminfo_t   *sp;            /* pointer to returned data */
     459             : 
     460             :         /*
     461             :          * Compute entry number in the summary file.
     462             :          */
     463   116500788 :         so = XFS_SUMOFFS(mp, log, bbno);
     464             :         /*
     465             :          * Compute the block number in the summary file.
     466             :          */
     467   116500788 :         sb = XFS_SUMOFFSTOBLOCK(mp, so);
     468             :         /*
     469             :          * If we have an old buffer, and the block number matches, use that.
     470             :          */
     471   116500788 :         if (*rbpp && *rsb == sb)
     472    97393806 :                 bp = *rbpp;
     473             :         /*
     474             :          * Otherwise we have to get the buffer.
     475             :          */
     476             :         else {
     477             :                 /*
     478             :                  * If there was an old one, get rid of it first.
     479             :                  */
     480    19106982 :                 if (*rbpp)
     481     9565400 :                         xfs_trans_brelse(tp, *rbpp);
     482    19106982 :                 error = xfs_rtbuf_get(mp, tp, sb, 1, &bp);
     483    19106982 :                 if (error) {
     484             :                         return error;
     485             :                 }
     486             :                 /*
     487             :                  * Remember this buffer and block for the next call.
     488             :                  */
     489    19106982 :                 *rbpp = bp;
     490    19106982 :                 *rsb = sb;
     491             :         }
     492             :         /*
     493             :          * Point to the summary information, modify/log it, and/or copy it out.
     494             :          */
     495   116500788 :         sp = XFS_SUMPTR(mp, bp, so);
     496   116500788 :         if (delta) {
     497    15647043 :                 uint first = (uint)((char *)sp - (char *)bp->b_addr);
     498             : 
     499    15647043 :                 *sp += delta;
     500    15647043 :                 if (mp->m_rsum_cache) {
     501    15647043 :                         if (*sp == 0 && log == mp->m_rsum_cache[bbno])
     502     2894102 :                                 mp->m_rsum_cache[bbno]++;
     503    15647043 :                         if (*sp != 0 && log < mp->m_rsum_cache[bbno])
     504     2997809 :                                 mp->m_rsum_cache[bbno] = log;
     505             :                 }
     506    15647043 :                 xfs_trans_log_buf(tp, bp, first, first + sizeof(*sp) - 1);
     507             :         }
     508   116500788 :         if (sum)
     509   100853745 :                 *sum = *sp;
     510             :         return 0;
     511             : }
     512             : 
     513             : int
     514    11936969 : xfs_rtmodify_summary(
     515             :         xfs_mount_t     *mp,            /* file system mount structure */
     516             :         xfs_trans_t     *tp,            /* transaction pointer */
     517             :         int             log,            /* log2 of extent size */
     518             :         xfs_rtblock_t   bbno,           /* bitmap block number */
     519             :         int             delta,          /* change to make to summary info */
     520             :         struct xfs_buf  **rbpp,         /* in/out: summary block buffer */
     521             :         xfs_fsblock_t   *rsb)           /* in/out: summary block number */
     522             : {
     523    11936969 :         return xfs_rtmodify_summary_int(mp, tp, log, bbno,
     524             :                                         delta, rbpp, rsb, NULL);
     525             : }
     526             : 
     527             : /*
     528             :  * Set the given range of bitmap bits to the given value.
     529             :  * Do whatever I/O and logging is required.
     530             :  */
     531             : int
     532     9541577 : xfs_rtmodify_range(
     533             :         xfs_mount_t     *mp,            /* file system mount point */
     534             :         xfs_trans_t     *tp,            /* transaction pointer */
     535             :         xfs_rtblock_t   start,          /* starting block to modify */
     536             :         xfs_extlen_t    len,            /* length of extent to modify */
     537             :         int             val)            /* 1 for free, 0 for allocated */
     538             : {
     539     9541577 :         xfs_rtword_t    *b;             /* current word in buffer */
     540     9541577 :         int             bit;            /* bit number in the word */
     541     9541577 :         xfs_rtblock_t   block;          /* bitmap block number */
     542     9541577 :         struct xfs_buf  *bp;            /* buf for the block */
     543     9541577 :         xfs_rtword_t    *bufp;          /* starting word in buffer */
     544     9541577 :         int             error;          /* error value */
     545     9541577 :         xfs_rtword_t    *first;         /* first used word in the buffer */
     546     9541577 :         int             i;              /* current bit number rel. to start */
     547     9541577 :         int             lastbit;        /* last useful bit in word */
     548     9541577 :         xfs_rtword_t    mask;           /* mask o frelevant bits for value */
     549     9541577 :         int             word;           /* word number in the buffer */
     550             : 
     551             :         /*
     552             :          * Compute starting bitmap block number.
     553             :          */
     554     9541577 :         block = XFS_BITTOBLOCK(mp, start);
     555             :         /*
     556             :          * Read the bitmap block, and point to its data.
     557             :          */
     558     9541577 :         error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
     559     9541577 :         if (error) {
     560             :                 return error;
     561             :         }
     562     9541577 :         bufp = bp->b_addr;
     563             :         /*
     564             :          * Compute the starting word's address, and starting bit.
     565             :          */
     566     9541577 :         word = XFS_BITTOWORD(mp, start);
     567     9541577 :         first = b = &bufp[word];
     568     9541577 :         bit = (int)(start & (XFS_NBWORD - 1));
     569             :         /*
     570             :          * 0 (allocated) => all zeroes; 1 (free) => all ones.
     571             :          */
     572     9541577 :         val = -val;
     573             :         /*
     574             :          * If not starting on a word boundary, deal with the first
     575             :          * (partial) word.
     576             :          */
     577     9541577 :         if (bit) {
     578             :                 /*
     579             :                  * Compute first bit not changed and mask of relevant bits.
     580             :                  */
     581     9195617 :                 lastbit = XFS_RTMIN(bit + len, XFS_NBWORD);
     582     9195617 :                 mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit;
     583             :                 /*
     584             :                  * Set/clear the active bits.
     585             :                  */
     586     9195617 :                 if (val)
     587     2609428 :                         *b |= mask;
     588             :                 else
     589     6586189 :                         *b &= ~mask;
     590     9195617 :                 i = lastbit - bit;
     591             :                 /*
     592             :                  * Go on to the next block if that's where the next word is
     593             :                  * and we need the next word.
     594             :                  */
     595     9195617 :                 if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
     596             :                         /*
     597             :                          * Log the changed part of this block.
     598             :                          * Get the next one.
     599             :                          */
     600        1282 :                         xfs_trans_log_buf(tp, bp,
     601             :                                 (uint)((char *)first - (char *)bufp),
     602             :                                 (uint)((char *)b - (char *)bufp));
     603        1282 :                         error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
     604        1282 :                         if (error) {
     605             :                                 return error;
     606             :                         }
     607        1282 :                         first = b = bufp = bp->b_addr;
     608        1282 :                         word = 0;
     609             :                 } else {
     610             :                         /*
     611             :                          * Go on to the next word in the buffer
     612             :                          */
     613     9194335 :                         b++;
     614             :                 }
     615             :         } else {
     616             :                 /*
     617             :                  * Starting on a word boundary, no partial word.
     618             :                  */
     619             :                 i = 0;
     620             :         }
     621             :         /*
     622             :          * Loop over whole words in buffers.  When we use up one buffer
     623             :          * we move on to the next one.
     624             :          */
     625    11773675 :         while (len - i >= XFS_NBWORD) {
     626             :                 /*
     627             :                  * Set the word value correctly.
     628             :                  */
     629     2232098 :                 *b = val;
     630     2232098 :                 i += XFS_NBWORD;
     631             :                 /*
     632             :                  * Go on to the next block if that's where the next word is
     633             :                  * and we need the next word.
     634             :                  */
     635     2232098 :                 if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
     636             :                         /*
     637             :                          * Log the changed part of this block.
     638             :                          * Get the next one.
     639             :                          */
     640         924 :                         xfs_trans_log_buf(tp, bp,
     641         924 :                                 (uint)((char *)first - (char *)bufp),
     642         924 :                                 (uint)((char *)b - (char *)bufp));
     643         924 :                         error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
     644         924 :                         if (error) {
     645           0 :                                 return error;
     646             :                         }
     647         924 :                         first = b = bufp = bp->b_addr;
     648         924 :                         word = 0;
     649             :                 } else {
     650             :                         /*
     651             :                          * Go on to the next word in the buffer
     652             :                          */
     653     2231174 :                         b++;
     654             :                 }
     655             :         }
     656             :         /*
     657             :          * If not ending on a word boundary, deal with the last
     658             :          * (partial) word.
     659             :          */
     660     9541577 :         if ((lastbit = len - i)) {
     661             :                 /*
     662             :                  * Compute a mask of relevant bits.
     663             :                  */
     664     4225949 :                 mask = ((xfs_rtword_t)1 << lastbit) - 1;
     665             :                 /*
     666             :                  * Set/clear the active bits.
     667             :                  */
     668     4225949 :                 if (val)
     669     1123969 :                         *b |= mask;
     670             :                 else
     671     3101980 :                         *b &= ~mask;
     672     4225949 :                 b++;
     673             :         }
     674             :         /*
     675             :          * Log any remaining changed bytes.
     676             :          */
     677     9541577 :         if (b > first)
     678     9541577 :                 xfs_trans_log_buf(tp, bp, (uint)((char *)first - (char *)bufp),
     679     9541577 :                         (uint)((char *)b - (char *)bufp - 1));
     680             :         return 0;
     681             : }
     682             : 
     683             : /*
     684             :  * Mark an extent specified by start and len freed.
     685             :  * Updates all the summary information as well as the bitmap.
     686             :  */
     687             : int
     688     2716341 : xfs_rtfree_range(
     689             :         xfs_mount_t     *mp,            /* file system mount point */
     690             :         xfs_trans_t     *tp,            /* transaction pointer */
     691             :         xfs_rtblock_t   start,          /* starting block to free */
     692             :         xfs_extlen_t    len,            /* length to free */
     693             :         struct xfs_buf  **rbpp,         /* in/out: summary block buffer */
     694             :         xfs_fsblock_t   *rsb)           /* in/out: summary block number */
     695             : {
     696     2716341 :         xfs_rtblock_t   end;            /* end of the freed extent */
     697     2716341 :         int             error;          /* error value */
     698     2716341 :         xfs_rtblock_t   postblock;      /* first block freed > end */
     699     2716341 :         xfs_rtblock_t   preblock;       /* first block freed < start */
     700             : 
     701     2716341 :         end = start + len - 1;
     702             :         /*
     703             :          * Modify the bitmap to mark this extent freed.
     704             :          */
     705     2716341 :         error = xfs_rtmodify_range(mp, tp, start, len, 1);
     706     2716341 :         if (error) {
     707             :                 return error;
     708             :         }
     709             :         /*
     710             :          * Assume we're freeing out of the middle of an allocated extent.
     711             :          * We need to find the beginning and end of the extent so we can
     712             :          * properly update the summary.
     713             :          */
     714     2716341 :         error = xfs_rtfind_back(mp, tp, start, 0, &preblock);
     715     2716341 :         if (error) {
     716             :                 return error;
     717             :         }
     718             :         /*
     719             :          * Find the next allocated block (end of allocated extent).
     720             :          */
     721     2716341 :         error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1,
     722             :                 &postblock);
     723     2716341 :         if (error)
     724             :                 return error;
     725             :         /*
     726             :          * If there are blocks not being freed at the front of the
     727             :          * old extent, add summary data for them to be allocated.
     728             :          */
     729     2716341 :         if (preblock < start) {
     730      306209 :                 error = xfs_rtmodify_summary(mp, tp,
     731             :                         XFS_RTBLOCKLOG(start - preblock),
     732      306209 :                         XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb);
     733      306209 :                 if (error) {
     734             :                         return error;
     735             :                 }
     736             :         }
     737             :         /*
     738             :          * If there are blocks not being freed at the end of the
     739             :          * old extent, add summary data for them to be allocated.
     740             :          */
     741     2716341 :         if (postblock > end) {
     742      687524 :                 error = xfs_rtmodify_summary(mp, tp,
     743             :                         XFS_RTBLOCKLOG(postblock - end),
     744      687524 :                         XFS_BITTOBLOCK(mp, end + 1), -1, rbpp, rsb);
     745      687524 :                 if (error) {
     746             :                         return error;
     747             :                 }
     748             :         }
     749             :         /*
     750             :          * Increment the summary information corresponding to the entire
     751             :          * (new) free extent.
     752             :          */
     753     5432682 :         error = xfs_rtmodify_summary(mp, tp,
     754     2716341 :                 XFS_RTBLOCKLOG(postblock + 1 - preblock),
     755     2716341 :                 XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb);
     756     2716341 :         return error;
     757             : }
     758             : 
     759             : /*
     760             :  * Check that the given range is either all allocated (val = 0) or
     761             :  * all free (val = 1).
     762             :  */
     763             : int
     764   298738914 : xfs_rtcheck_range(
     765             :         xfs_mount_t     *mp,            /* file system mount point */
     766             :         xfs_trans_t     *tp,            /* transaction pointer */
     767             :         xfs_rtblock_t   start,          /* starting block number of extent */
     768             :         xfs_extlen_t    len,            /* length of extent */
     769             :         int             val,            /* 1 for free, 0 for allocated */
     770             :         xfs_rtblock_t   *new,           /* out: first block not matching */
     771             :         int             *stat)          /* out: 1 for matches, 0 for not */
     772             : {
     773   298738914 :         xfs_rtword_t    *b;             /* current word in buffer */
     774   298738914 :         int             bit;            /* bit number in the word */
     775   298738914 :         xfs_rtblock_t   block;          /* bitmap block number */
     776   298738914 :         struct xfs_buf  *bp;            /* buf for the block */
     777   298738914 :         xfs_rtword_t    *bufp;          /* starting word in buffer */
     778   298738914 :         int             error;          /* error value */
     779   298738914 :         xfs_rtblock_t   i;              /* current bit number rel. to start */
     780   298738914 :         xfs_rtblock_t   lastbit;        /* last useful bit in word */
     781   298738914 :         xfs_rtword_t    mask;           /* mask of relevant bits for value */
     782   298738914 :         xfs_rtword_t    wdiff;          /* difference from wanted value */
     783   298738914 :         int             word;           /* word number in the buffer */
     784             : 
     785             :         /*
     786             :          * Compute starting bitmap block number
     787             :          */
     788   298738914 :         block = XFS_BITTOBLOCK(mp, start);
     789             :         /*
     790             :          * Read the bitmap block.
     791             :          */
     792   298738914 :         error = xfs_rtbuf_get(mp, tp, block, 0, &bp);
     793   298737703 :         if (error) {
     794             :                 return error;
     795             :         }
     796   298737703 :         bufp = bp->b_addr;
     797             :         /*
     798             :          * Compute the starting word's address, and starting bit.
     799             :          */
     800   298737703 :         word = XFS_BITTOWORD(mp, start);
     801   298737703 :         b = &bufp[word];
     802   298737703 :         bit = (int)(start & (XFS_NBWORD - 1));
     803             :         /*
     804             :          * 0 (allocated) => all zero's; 1 (free) => all one's.
     805             :          */
     806   298737703 :         val = -val;
     807             :         /*
     808             :          * If not starting on a word boundary, deal with the first
     809             :          * (partial) word.
     810             :          */
     811   298737703 :         if (bit) {
     812             :                 /*
     813             :                  * Compute first bit not examined.
     814             :                  */
     815   275667195 :                 lastbit = XFS_RTMIN(bit + len, XFS_NBWORD);
     816             :                 /*
     817             :                  * Mask of relevant bits.
     818             :                  */
     819   275667195 :                 mask = (((xfs_rtword_t)1 << (lastbit - bit)) - 1) << bit;
     820             :                 /*
     821             :                  * Compute difference between actual and desired value.
     822             :                  */
     823   275667195 :                 if ((wdiff = (*b ^ val) & mask)) {
     824             :                         /*
     825             :                          * Different, compute first wrong bit and return.
     826             :                          */
     827   230095358 :                         xfs_trans_brelse(tp, bp);
     828   230104962 :                         i = XFS_RTLOBIT(wdiff) - bit;
     829   230104962 :                         *new = start + i;
     830   230104962 :                         *stat = 0;
     831   230104962 :                         return 0;
     832             :                 }
     833    45571837 :                 i = lastbit - bit;
     834             :                 /*
     835             :                  * Go on to next block if that's where the next word is
     836             :                  * and we need the next word.
     837             :                  */
     838    45571837 :                 if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
     839             :                         /*
     840             :                          * If done with this block, get the next one.
     841             :                          */
     842        5966 :                         xfs_trans_brelse(tp, bp);
     843        5966 :                         error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
     844        5966 :                         if (error) {
     845             :                                 return error;
     846             :                         }
     847        5966 :                         b = bufp = bp->b_addr;
     848        5966 :                         word = 0;
     849             :                 } else {
     850             :                         /*
     851             :                          * Go on to the next word in the buffer.
     852             :                          */
     853    45565871 :                         b++;
     854             :                 }
     855             :         } else {
     856             :                 /*
     857             :                  * Starting on a word boundary, no partial word.
     858             :                  */
     859             :                 i = 0;
     860             :         }
     861             :         /*
     862             :          * Loop over whole words in buffers.  When we use up one buffer
     863             :          * we move on to the next one.
     864             :          */
     865    71122061 :         while (len - i >= XFS_NBWORD) {
     866             :                 /*
     867             :                  * Compute difference between actual and desired value.
     868             :                  */
     869     7505312 :                 if ((wdiff = *b ^ val)) {
     870             :                         /*
     871             :                          * Different, compute first wrong bit and return.
     872             :                          */
     873     5025599 :                         xfs_trans_brelse(tp, bp);
     874     5025599 :                         i += XFS_RTLOBIT(wdiff);
     875     5025599 :                         *new = start + i;
     876     5025599 :                         *stat = 0;
     877     5025599 :                         return 0;
     878             :                 }
     879     2479713 :                 i += XFS_NBWORD;
     880             :                 /*
     881             :                  * Go on to next block if that's where the next word is
     882             :                  * and we need the next word.
     883             :                  */
     884     2479713 :                 if (++word == XFS_BLOCKWSIZE(mp) && i < len) {
     885             :                         /*
     886             :                          * If done with this block, get the next one.
     887             :                          */
     888        1915 :                         xfs_trans_brelse(tp, bp);
     889        1918 :                         error = xfs_rtbuf_get(mp, tp, ++block, 0, &bp);
     890        1918 :                         if (error) {
     891           0 :                                 return error;
     892             :                         }
     893        1918 :                         b = bufp = bp->b_addr;
     894        1918 :                         word = 0;
     895             :                 } else {
     896             :                         /*
     897             :                          * Go on to the next word in the buffer.
     898             :                          */
     899     2477798 :                         b++;
     900             :                 }
     901             :         }
     902             :         /*
     903             :          * If not ending on a word boundary, deal with the last
     904             :          * (partial) word.
     905             :          */
     906    63616749 :         if ((lastbit = len - i)) {
     907             :                 /*
     908             :                  * Mask of relevant bits.
     909             :                  */
     910    25474351 :                 mask = ((xfs_rtword_t)1 << lastbit) - 1;
     911             :                 /*
     912             :                  * Compute difference between actual and desired value.
     913             :                  */
     914    25474351 :                 if ((wdiff = (*b ^ val) & mask)) {
     915             :                         /*
     916             :                          * Different, compute first wrong bit and return.
     917             :                          */
     918    20330177 :                         xfs_trans_brelse(tp, bp);
     919    20330187 :                         i += XFS_RTLOBIT(wdiff);
     920    20330187 :                         *new = start + i;
     921    20330187 :                         *stat = 0;
     922    20330187 :                         return 0;
     923             :                 } else
     924             :                         i = len;
     925             :         }
     926             :         /*
     927             :          * Successful, return.
     928             :          */
     929    43286572 :         xfs_trans_brelse(tp, bp);
     930    43286571 :         *new = start + i;
     931    43286571 :         *stat = 1;
     932    43286571 :         return 0;
     933             : }
     934             : 
     935             : #ifdef DEBUG
     936             : /*
     937             :  * Check that the given extent (block range) is allocated already.
     938             :  */
     939             : STATIC int                              /* error */
     940     2716336 : xfs_rtcheck_alloc_range(
     941             :         xfs_mount_t     *mp,            /* file system mount point */
     942             :         xfs_trans_t     *tp,            /* transaction pointer */
     943             :         xfs_rtblock_t   bno,            /* starting block number of extent */
     944             :         xfs_extlen_t    len)            /* length of extent */
     945             : {
     946     2716336 :         xfs_rtblock_t   new;            /* dummy for xfs_rtcheck_range */
     947     2716336 :         int             stat;
     948     2716336 :         int             error;
     949             : 
     950     2716336 :         error = xfs_rtcheck_range(mp, tp, bno, len, 0, &new, &stat);
     951     2716336 :         if (error)
     952             :                 return error;
     953     2716336 :         ASSERT(stat);
     954             :         return 0;
     955             : }
     956             : #else
     957             : #define xfs_rtcheck_alloc_range(m,t,b,l)        (0)
     958             : #endif
     959             : /*
     960             :  * Free an extent in the realtime subvolume.  Length is expressed in
     961             :  * realtime extents, as is the block number.
     962             :  */
     963             : int                                     /* error */
     964     2716336 : xfs_rtfree_extent(
     965             :         xfs_trans_t     *tp,            /* transaction pointer */
     966             :         xfs_rtblock_t   bno,            /* starting block number to free */
     967             :         xfs_extlen_t    len)            /* length of extent freed */
     968             : {
     969     2716336 :         int             error;          /* error value */
     970     2716336 :         xfs_mount_t     *mp;            /* file system mount structure */
     971     2716336 :         xfs_fsblock_t   sb;             /* summary file block number */
     972     2716336 :         struct xfs_buf  *sumbp = NULL;  /* summary file block buffer */
     973             : 
     974     2716336 :         mp = tp->t_mountp;
     975             : 
     976     2716336 :         ASSERT(mp->m_rbmip->i_itemp != NULL);
     977     2716336 :         ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
     978             : 
     979     2716336 :         error = xfs_rtcheck_alloc_range(mp, tp, bno, len);
     980     2716336 :         if (error)
     981             :                 return error;
     982             : 
     983             :         /*
     984             :          * Free the range of realtime blocks.
     985             :          */
     986     2716336 :         error = xfs_rtfree_range(mp, tp, bno, len, &sumbp, &sb);
     987     2716336 :         if (error) {
     988             :                 return error;
     989             :         }
     990             :         /*
     991             :          * Mark more blocks free in the superblock.
     992             :          */
     993     2716336 :         xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, (long)len);
     994             :         /*
     995             :          * If we've now freed all the blocks, reset the file sequence
     996             :          * number to 0.
     997             :          */
     998     2716336 :         if (tp->t_frextents_delta + mp->m_sb.sb_frextents ==
     999     2716336 :             mp->m_sb.sb_rextents) {
    1000        1146 :                 if (!(mp->m_rbmip->i_diflags & XFS_DIFLAG_NEWRTBM))
    1001           0 :                         mp->m_rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
    1002        1146 :                 *(uint64_t *)&VFS_I(mp->m_rbmip)->i_atime = 0;
    1003        1146 :                 xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
    1004             :         }
    1005             :         return 0;
    1006             : }
    1007             : 
    1008             : /* Find all the free records within a given range. */
    1009             : int
    1010      276317 : xfs_rtalloc_query_range(
    1011             :         struct xfs_mount                *mp,
    1012             :         struct xfs_trans                *tp,
    1013             :         const struct xfs_rtalloc_rec    *low_rec,
    1014             :         const struct xfs_rtalloc_rec    *high_rec,
    1015             :         xfs_rtalloc_query_range_fn      fn,
    1016             :         void                            *priv)
    1017             : {
    1018      276317 :         struct xfs_rtalloc_rec          rec;
    1019      276317 :         xfs_rtblock_t                   rtstart;
    1020      276317 :         xfs_rtblock_t                   rtend;
    1021      276317 :         xfs_rtblock_t                   high_key;
    1022      276317 :         int                             is_free;
    1023      276317 :         int                             error = 0;
    1024             : 
    1025      276317 :         if (low_rec->ar_startext > high_rec->ar_startext)
    1026             :                 return -EINVAL;
    1027      276317 :         if (low_rec->ar_startext >= mp->m_sb.sb_rextents ||
    1028             :             low_rec->ar_startext == high_rec->ar_startext)
    1029             :                 return 0;
    1030             : 
    1031      276317 :         high_key = min(high_rec->ar_startext, mp->m_sb.sb_rextents - 1);
    1032             : 
    1033             :         /* Iterate the bitmap, looking for discrepancies. */
    1034      276317 :         rtstart = low_rec->ar_startext;
    1035    70749453 :         while (rtstart <= high_key) {
    1036             :                 /* Is the first block free? */
    1037    70473576 :                 error = xfs_rtcheck_range(mp, tp, rtstart, 1, 1, &rtend,
    1038             :                                 &is_free);
    1039    70473576 :                 if (error)
    1040             :                         break;
    1041             : 
    1042             :                 /* How long does the extent go for? */
    1043    70473576 :                 error = xfs_rtfind_forw(mp, tp, rtstart, high_key, &rtend);
    1044    70473576 :                 if (error)
    1045             :                         break;
    1046             : 
    1047    70473576 :                 if (is_free) {
    1048    35306260 :                         rec.ar_startext = rtstart;
    1049    35306260 :                         rec.ar_extcount = rtend - rtstart + 1;
    1050             : 
    1051    35306260 :                         error = fn(mp, tp, &rec, priv);
    1052    35306260 :                         if (error)
    1053             :                                 break;
    1054             :                 }
    1055             : 
    1056    70473136 :                 rtstart = rtend + 1;
    1057             :         }
    1058             : 
    1059             :         return error;
    1060             : }
    1061             : 
    1062             : /* Find all the free records. */
    1063             : int
    1064      226107 : xfs_rtalloc_query_all(
    1065             :         struct xfs_mount                *mp,
    1066             :         struct xfs_trans                *tp,
    1067             :         xfs_rtalloc_query_range_fn      fn,
    1068             :         void                            *priv)
    1069             : {
    1070      226107 :         struct xfs_rtalloc_rec          keys[2];
    1071             : 
    1072      226107 :         keys[0].ar_startext = 0;
    1073      226107 :         keys[1].ar_startext = mp->m_sb.sb_rextents - 1;
    1074      226107 :         keys[0].ar_extcount = keys[1].ar_extcount = 0;
    1075             : 
    1076      226107 :         return xfs_rtalloc_query_range(mp, tp, &keys[0], &keys[1], fn, priv);
    1077             : }
    1078             : 
    1079             : /* Is the given extent all free? */
    1080             : int
    1081   163561986 : xfs_rtalloc_extent_is_free(
    1082             :         struct xfs_mount                *mp,
    1083             :         struct xfs_trans                *tp,
    1084             :         xfs_rtblock_t                   start,
    1085             :         xfs_extlen_t                    len,
    1086             :         bool                            *is_free)
    1087             : {
    1088   163561986 :         xfs_rtblock_t                   end;
    1089   163561986 :         int                             matches;
    1090   163561986 :         int                             error;
    1091             : 
    1092   163561986 :         error = xfs_rtcheck_range(mp, tp, start, len, 1, &end, &matches);
    1093   163567970 :         if (error)
    1094             :                 return error;
    1095             : 
    1096   163567970 :         *is_free = matches;
    1097   163567970 :         return 0;
    1098             : }

Generated by: LCOV version 1.14