LCOV - code coverage report
Current view: top level - libgfs2 - recovery.c (source / functions) Coverage Total Hit
Test: gfs2-utils.info Lines: 60.5 % 114 69
Test Date: 2024-03-07 16:24:06 Functions: 75.0 % 8 6

            Line data    Source code
       1              : #include "clusterautoconfig.h"
       2              : 
       3              : /*
       4              :  * NOTE:
       5              :  *
       6              :  * This code was pilfered from the gfs2 kernel and adapted to userland.
       7              :  * If you change this part, you should evaluate whether the upstream kernel
       8              :  * version of recovery.c should be changed as well.  Likewise, if the
       9              :  * upstream version changes, this part should be kept in sync.
      10              :  * 
      11              :  */
      12              : 
      13              : #include <errno.h>
      14              : #include <string.h>
      15              : #include "libgfs2.h"
      16              : 
      17            0 : void lgfs2_replay_incr_blk(struct lgfs2_inode *ip, unsigned int *blk)
      18              : {
      19            0 :         uint32_t jd_blocks = ip->i_size / ip->i_sbd->sd_bsize;
      20              : 
      21            0 :         if (++*blk == jd_blocks)
      22            0 :                 *blk = 0;
      23            0 : }
      24              : 
      25      1927125 : int lgfs2_replay_read_block(struct lgfs2_inode *ip, unsigned int blk,
      26              :                            struct lgfs2_buffer_head **bh)
      27              : {
      28      1927125 :         int new = 0;
      29              :         uint64_t dblock;
      30              : 
      31      1927125 :         if (lgfs2_block_map(ip, blk, &new, &dblock, NULL, 0))
      32            0 :                 return -EINVAL;
      33      1927125 :         if (!dblock)
      34            0 :                 return -EIO;
      35              : 
      36      1927125 :         *bh = lgfs2_bread(ip->i_sbd, dblock);
      37      1927125 :         return 0;
      38              : }
      39              : 
      40      1927125 : static void log_header_in(struct lgfs2_log_header *lh, char *buf)
      41              : {
      42      1927125 :         struct gfs2_log_header *lhd = (struct gfs2_log_header *)buf;
      43              : 
      44      1927125 :         lh->lh_sequence = be64_to_cpu(lhd->lh_sequence);
      45      1927125 :         lh->lh_flags = be32_to_cpu(lhd->lh_flags);
      46      1927125 :         lh->lh_tail = be32_to_cpu(lhd->lh_tail);
      47      1927125 :         lh->lh_blkno = be32_to_cpu(lhd->lh_blkno);
      48      1927125 :         lh->lh_hash = be32_to_cpu(lhd->lh_hash);
      49      1927125 :         lh->lh_crc = be32_to_cpu(lhd->lh_crc);
      50      1927125 :         lh->lh_local_total = be64_to_cpu(lhd->lh_local_total);
      51      1927125 :         lh->lh_local_free = be64_to_cpu(lhd->lh_local_free);
      52      1927125 :         lh->lh_local_dinodes = be64_to_cpu(lhd->lh_local_dinodes);
      53      1927125 : }
      54              : 
      55              : /**
      56              :  * get_log_header - read the log header for a given segment
      57              :  * @ip: the journal incore inode
      58              :  * @blk: the block to look at
      59              :  * @lh: the log header to return
      60              :  *
      61              :  * Read the log header for a given segement in a given journal.  Do a few
      62              :  * sanity checks on it.
      63              :  *
      64              :  * Returns: 0 on success,
      65              :  *          1 if the header was invalid or incomplete,
      66              :  *          errno on error
      67              :  */
      68              : 
      69      1927125 : int lgfs2_get_log_header(struct lgfs2_inode *ip, unsigned int blk,
      70              :                          struct lgfs2_log_header *head)
      71              : {
      72              :         struct lgfs2_buffer_head *bh;
      73              :         struct lgfs2_log_header lh;
      74              :         struct gfs2_log_header *tmp;
      75              :         __be32 saved_hash;
      76              :         uint32_t hash;
      77      1927125 :         uint32_t lh_crc = 0;
      78              :         uint32_t crc;
      79              :         int error;
      80              : 
      81      1927125 :         error = lgfs2_replay_read_block(ip, blk, &bh);
      82      1927125 :         if (error)
      83            0 :                 return error;
      84              : 
      85      1927125 :         tmp = (struct gfs2_log_header *)bh->b_data;
      86      1927125 :         saved_hash = tmp->lh_hash;
      87      1927125 :         tmp->lh_hash = 0;
      88      1927125 :         hash = lgfs2_log_header_hash(bh->b_data);
      89      1927125 :         tmp->lh_hash = saved_hash;
      90      1927125 :         crc = lgfs2_log_header_crc(bh->b_data, ip->i_sbd->sd_bsize);
      91      1927125 :         log_header_in(&lh, bh->b_data);
      92      1927125 :         lgfs2_brelse(bh);
      93      1927125 :         lh_crc = lh.lh_crc;
      94      1927125 :         if (error || lh.lh_blkno != blk || lh.lh_hash != hash)
      95            0 :                 return 1;
      96              :         /* Don't check the crc if it's zero, as it is in pre-v2 log headers */
      97      1927125 :         if (lh_crc != 0 && lh_crc != crc)
      98            0 :                 return 1;
      99              : 
     100      1927125 :         *head = lh;
     101              : 
     102      1927125 :         return 0;
     103              : }
     104              : 
     105              : /**
     106              :  * find_good_lh - find a good log header
     107              :  * @ip: the journal incore inode
     108              :  * @blk: the segment to start searching from
     109              :  * @lh: the log header to fill in
     110              :  * @forward: if true search forward in the log, else search backward
     111              :  *
     112              :  * Call get_log_header() to get a log header for a segment, but if the
     113              :  * segment is bad, either scan forward or backward until we find a good one.
     114              :  *
     115              :  * Returns: errno
     116              :  */
     117         1942 : static int find_good_lh(struct lgfs2_inode *ip, unsigned int *blk, struct lgfs2_log_header *head)
     118              : {
     119         1942 :         unsigned int orig_blk = *blk;
     120              :         int error;
     121         1942 :         uint32_t jd_blocks = ip->i_size / ip->i_sbd->sd_bsize;
     122              : 
     123              :         for (;;) {
     124         1942 :                 error = lgfs2_get_log_header(ip, *blk, head);
     125         1942 :                 if (error <= 0)
     126         1942 :                         return error;
     127              : 
     128            0 :                 if (++*blk == jd_blocks)
     129            0 :                         *blk = 0;
     130              : 
     131            0 :                 if (*blk == orig_blk)
     132            0 :                         return -EIO;
     133              :         }
     134              : }
     135              : 
     136              : /**
     137              :  * jhead_scan - make sure we've found the head of the log
     138              :  * @jd: the journal
     139              :  * @head: this is filled in with the log descriptor of the head
     140              :  *
     141              :  * At this point, seg and lh should be either the head of the log or just
     142              :  * before.  Scan forward until we find the head.
     143              :  *
     144              :  * Returns: errno
     145              :  */
     146              : 
     147           63 : static int jhead_scan(struct lgfs2_inode *ip, struct lgfs2_log_header *head)
     148              : {
     149           63 :         unsigned int blk = head->lh_blkno;
     150           63 :         uint32_t jd_blocks = ip->i_size / ip->i_sbd->sd_bsize;
     151              :         struct lgfs2_log_header lh;
     152              :         int error;
     153              : 
     154              :         for (;;) {
     155           63 :                 if (++blk == jd_blocks)
     156            0 :                         blk = 0;
     157              : 
     158           63 :                 error = lgfs2_get_log_header(ip, blk, &lh);
     159           63 :                 if (error < 0)
     160            0 :                         return error;
     161           63 :                 if (error == 1)
     162            0 :                         continue;
     163              : 
     164           63 :                 if (lh.lh_sequence == head->lh_sequence)
     165            0 :                         return -EIO;
     166           63 :                 if (lh.lh_sequence < head->lh_sequence)
     167           63 :                         break;
     168              : 
     169            0 :                 *head = lh;
     170              :         }
     171              : 
     172           63 :         return 0;
     173              : }
     174              : 
     175              : /**
     176              :  * gfs2_find_jhead - find the head of a log
     177              :  * @jd: the journal
     178              :  * @head: the log descriptor for the head of the log is returned here
     179              :  *
     180              :  * Do a binary search of a journal and find the valid log entry with the
     181              :  * highest sequence number.  (i.e. the log head)
     182              :  *
     183              :  * Returns: errno
     184              :  */
     185              : 
     186           63 : int lgfs2_find_jhead(struct lgfs2_inode *ip, struct lgfs2_log_header *head)
     187              : {
     188              :         struct lgfs2_log_header lh_1, lh_m;
     189              :         uint32_t blk_1, blk_2, blk_m;
     190           63 :         uint32_t jd_blocks = ip->i_size / ip->i_sbd->sd_bsize;
     191              :         int error;
     192              : 
     193           63 :         blk_1 = 0;
     194           63 :         blk_2 = jd_blocks - 1;
     195              : 
     196              :         for (;;) {
     197          971 :                 blk_m = (blk_1 + blk_2) / 2;
     198              : 
     199          971 :                 error = find_good_lh(ip, &blk_1, &lh_1);
     200          971 :                 if (error)
     201            0 :                         return error;
     202              : 
     203          971 :                 error = find_good_lh(ip, &blk_m, &lh_m);
     204          971 :                 if (error)
     205            0 :                         return error;
     206              : 
     207          971 :                 if (blk_1 == blk_m || blk_m == blk_2)
     208              :                         break;
     209              : 
     210          908 :                 if (lh_1.lh_sequence <= lh_m.lh_sequence)
     211          428 :                         blk_1 = blk_m;
     212              :                 else
     213          480 :                         blk_2 = blk_m;
     214              :         }
     215              : 
     216           63 :         error = jhead_scan(ip, &lh_1);
     217           63 :         if (error)
     218            0 :                 return error;
     219              : 
     220           63 :         *head = lh_1;
     221              : 
     222           63 :         return error;
     223              : }
     224              : 
     225              : /**
     226              :  * clean_journal - mark a dirty journal as being clean
     227              :  * @sdp: the filesystem
     228              :  * @jd: the journal
     229              :  * @head: the head journal to start from
     230              :  *
     231              :  * Returns: errno
     232              :  */
     233              : 
     234            0 : int lgfs2_clean_journal(struct lgfs2_inode *ip, struct lgfs2_log_header *head)
     235              : {
     236              :         unsigned int lblock;
     237              :         struct gfs2_log_header *lh;
     238              :         uint32_t hash;
     239              :         struct lgfs2_buffer_head *bh;
     240            0 :         int new = 0;
     241              :         uint64_t dblock;
     242              : 
     243            0 :         lblock = head->lh_blkno;
     244            0 :         lgfs2_replay_incr_blk(ip, &lblock);
     245            0 :         if (lgfs2_block_map(ip, lblock, &new, &dblock, NULL, 0))
     246            0 :                 return -EINVAL;
     247            0 :         if (!dblock)
     248            0 :                 return -EIO;
     249              : 
     250            0 :         bh = lgfs2_bread(ip->i_sbd, dblock);
     251            0 :         memset(bh->b_data, 0, ip->i_sbd->sd_bsize);
     252              : 
     253            0 :         lh = (struct gfs2_log_header *)bh->b_data;
     254            0 :         memset(lh, 0, sizeof(struct gfs2_log_header));
     255            0 :         lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
     256            0 :         lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
     257            0 :         lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH);
     258            0 :         lh->lh_sequence = cpu_to_be64(head->lh_sequence + 1);
     259            0 :         lh->lh_flags = cpu_to_be32(GFS2_LOG_HEAD_UNMOUNT);
     260            0 :         lh->lh_blkno = cpu_to_be32(lblock);
     261            0 :         hash = lgfs2_log_header_hash(bh->b_data);
     262            0 :         lh->lh_hash = cpu_to_be32(hash);
     263            0 :         lgfs2_bmodified(bh);
     264            0 :         lgfs2_brelse(bh);
     265              : 
     266            0 :         return 0;
     267              : }
     268              : 
        

Generated by: LCOV version 2.0-1