LCOV - code coverage report
Current view: top level - libgfs2 - recovery.c (source / functions) Hit Total Coverage
Test: gfs2-utils.info Lines: 69 114 60.5 %
Date: 2023-10-25 12:04:14 Functions: 6 8 75.0 %

          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     1894324 : int lgfs2_replay_read_block(struct lgfs2_inode *ip, unsigned int blk,
      26             :                            struct lgfs2_buffer_head **bh)
      27             : {
      28     1894324 :         int new = 0;
      29             :         uint64_t dblock;
      30             : 
      31     1894324 :         if (lgfs2_block_map(ip, blk, &new, &dblock, NULL, 0))
      32           0 :                 return -EINVAL;
      33     1894324 :         if (!dblock)
      34           0 :                 return -EIO;
      35             : 
      36     1894324 :         *bh = lgfs2_bread(ip->i_sbd, dblock);
      37     1894324 :         return 0;
      38             : }
      39             : 
      40     1894324 : static void log_header_in(struct lgfs2_log_header *lh, char *buf)
      41             : {
      42     1894324 :         struct gfs2_log_header *lhd = (struct gfs2_log_header *)buf;
      43             : 
      44     1894324 :         lh->lh_sequence = be64_to_cpu(lhd->lh_sequence);
      45     1894324 :         lh->lh_flags = be32_to_cpu(lhd->lh_flags);
      46     1894324 :         lh->lh_tail = be32_to_cpu(lhd->lh_tail);
      47     1894324 :         lh->lh_blkno = be32_to_cpu(lhd->lh_blkno);
      48     1894324 :         lh->lh_hash = be32_to_cpu(lhd->lh_hash);
      49     1894324 :         lh->lh_crc = be32_to_cpu(lhd->lh_crc);
      50     1894324 :         lh->lh_local_total = be64_to_cpu(lhd->lh_local_total);
      51     1894324 :         lh->lh_local_free = be64_to_cpu(lhd->lh_local_free);
      52     1894324 :         lh->lh_local_dinodes = be64_to_cpu(lhd->lh_local_dinodes);
      53     1894324 : }
      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     1894324 : 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     1894324 :         uint32_t lh_crc = 0;
      78             :         uint32_t crc;
      79             :         int error;
      80             : 
      81     1894324 :         error = lgfs2_replay_read_block(ip, blk, &bh);
      82     1894324 :         if (error)
      83           0 :                 return error;
      84             : 
      85     1894324 :         tmp = (struct gfs2_log_header *)bh->b_data;
      86     1894324 :         saved_hash = tmp->lh_hash;
      87     1894324 :         tmp->lh_hash = 0;
      88     1894324 :         hash = lgfs2_log_header_hash(bh->b_data);
      89     1894324 :         tmp->lh_hash = saved_hash;
      90     1894324 :         crc = lgfs2_log_header_crc(bh->b_data, ip->i_sbd->sd_bsize);
      91     1894324 :         log_header_in(&lh, bh->b_data);
      92     1894324 :         lgfs2_brelse(bh);
      93     1894324 :         lh_crc = lh.lh_crc;
      94     1894324 :         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     1894324 :         if (lh_crc != 0 && lh_crc != crc)
      98           0 :                 return 1;
      99             : 
     100     1894324 :         *head = lh;
     101             : 
     102     1894324 :         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        1910 : static int find_good_lh(struct lgfs2_inode *ip, unsigned int *blk, struct lgfs2_log_header *head)
     118             : {
     119        1910 :         unsigned int orig_blk = *blk;
     120             :         int error;
     121        1910 :         uint32_t jd_blocks = ip->i_size / ip->i_sbd->sd_bsize;
     122             : 
     123             :         for (;;) {
     124        1910 :                 error = lgfs2_get_log_header(ip, *blk, head);
     125        1910 :                 if (error <= 0)
     126        1910 :                         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          62 : static int jhead_scan(struct lgfs2_inode *ip, struct lgfs2_log_header *head)
     148             : {
     149          62 :         unsigned int blk = head->lh_blkno;
     150          62 :         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          62 :                 if (++blk == jd_blocks)
     156           0 :                         blk = 0;
     157             : 
     158          62 :                 error = lgfs2_get_log_header(ip, blk, &lh);
     159          62 :                 if (error < 0)
     160           0 :                         return error;
     161          62 :                 if (error == 1)
     162           0 :                         continue;
     163             : 
     164          62 :                 if (lh.lh_sequence == head->lh_sequence)
     165           0 :                         return -EIO;
     166          62 :                 if (lh.lh_sequence < head->lh_sequence)
     167          62 :                         break;
     168             : 
     169           0 :                 *head = lh;
     170             :         }
     171             : 
     172          62 :         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          62 : 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          62 :         uint32_t jd_blocks = ip->i_size / ip->i_sbd->sd_bsize;
     191             :         int error;
     192             : 
     193          62 :         blk_1 = 0;
     194          62 :         blk_2 = jd_blocks - 1;
     195             : 
     196             :         for (;;) {
     197         955 :                 blk_m = (blk_1 + blk_2) / 2;
     198             : 
     199         955 :                 error = find_good_lh(ip, &blk_1, &lh_1);
     200         955 :                 if (error)
     201           0 :                         return error;
     202             : 
     203         955 :                 error = find_good_lh(ip, &blk_m, &lh_m);
     204         955 :                 if (error)
     205           0 :                         return error;
     206             : 
     207         955 :                 if (blk_1 == blk_m || blk_m == blk_2)
     208             :                         break;
     209             : 
     210         893 :                 if (lh_1.lh_sequence <= lh_m.lh_sequence)
     211         435 :                         blk_1 = blk_m;
     212             :                 else
     213         458 :                         blk_2 = blk_m;
     214             :         }
     215             : 
     216          62 :         error = jhead_scan(ip, &lh_1);
     217          62 :         if (error)
     218           0 :                 return error;
     219             : 
     220          62 :         *head = lh_1;
     221             : 
     222          62 :         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 1.14