LCOV - code coverage report
Current view: top level - libubifs - commit.c (source / functions) Hit Total Coverage
Test: a simple test Lines: 108 151 71.5 %
Date: 2024-06-05 20:10:43 Functions: 3 6 50.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-only
       2             : /*
       3             :  * This file is part of UBIFS.
       4             :  *
       5             :  * Copyright (C) 2006-2008 Nokia Corporation.
       6             :  *
       7             :  * Authors: Adrian Hunter
       8             :  *          Artem Bityutskiy (Битюцкий Артём)
       9             :  */
      10             : 
      11             : /*
      12             :  * This file implements functions that manage the running of the commit process.
      13             :  * Each affected module has its own functions to accomplish their part in the
      14             :  * commit and those functions are called here.
      15             :  *
      16             :  * The commit is the process whereby all updates to the index and LEB properties
      17             :  * are written out together and the journal becomes empty. This keeps the
      18             :  * file system consistent - at all times the state can be recreated by reading
      19             :  * the index and LEB properties and then replaying the journal.
      20             :  *
      21             :  * The commit is split into two parts named "commit start" and "commit end".
      22             :  * During commit start, the commit process has exclusive access to the journal
      23             :  * by holding the commit semaphore down for writing. As few I/O operations as
      24             :  * possible are performed during commit start, instead the nodes that are to be
      25             :  * written are merely identified. During commit end, the commit semaphore is no
      26             :  * longer held and the journal is again in operation, allowing users to continue
      27             :  * to use the file system while the bulk of the commit I/O is performed. The
      28             :  * purpose of this two-step approach is to prevent the commit from causing any
      29             :  * latency blips. Note that in any case, the commit does not prevent lookups
      30             :  * (as permitted by the TNC mutex), or access to VFS data structures e.g. page
      31             :  * cache.
      32             :  */
      33             : 
      34             : #include "linux_err.h"
      35             : #include "bitops.h"
      36             : #include "kmem.h"
      37             : #include "ubifs.h"
      38             : #include "debug.h"
      39             : #include "defs.h"
      40             : #include "misc.h"
      41             : 
      42             : /*
      43             :  * nothing_to_commit - check if there is nothing to commit.
      44             :  * @c: UBIFS file-system description object
      45             :  *
      46             :  * This is a helper function which checks if there is anything to commit. It is
      47             :  * used as an optimization to avoid starting the commit if it is not really
      48             :  * necessary. Indeed, the commit operation always assumes flash I/O (e.g.,
      49             :  * writing the commit start node to the log), and it is better to avoid doing
      50             :  * this unnecessarily. E.g., 'ubifs_sync_fs()' runs the commit, but if there is
      51             :  * nothing to commit, it is more optimal to avoid any flash I/O.
      52             :  *
      53             :  * This function has to be called with @c->commit_sem locked for writing -
      54             :  * this function does not take LPT/TNC locks because the @c->commit_sem
      55             :  * guarantees that we have exclusive access to the TNC and LPT data structures.
      56             :  *
      57             :  * This function returns %1 if there is nothing to commit and %0 otherwise.
      58             :  */
      59        3532 : static int nothing_to_commit(struct ubifs_info *c)
      60             : {
      61             :         /*
      62             :          * During mounting or remounting from R/O mode to R/W mode we may
      63             :          * commit for various recovery-related reasons.
      64             :          */
      65        3532 :         if (c->mounting || c->remounting_rw)
      66             :                 return 0;
      67             : 
      68             :         /*
      69             :          * If the root TNC node is dirty, we definitely have something to
      70             :          * commit.
      71             :          */
      72        3736 :         if (c->zroot.znode && ubifs_zn_dirty(c->zroot.znode))
      73             :                 return 0;
      74             : 
      75             :         /*
      76             :          * Increasing @c->dirty_pn_cnt/@c->dirty_nn_cnt and marking
      77             :          * nnodes/pnodes as dirty in run_gc() could race with following
      78             :          * checking, which leads inconsistent states between @c->nroot
      79             :          * and @c->dirty_pn_cnt/@c->dirty_nn_cnt, holding @c->lp_mutex
      80             :          * to avoid that.
      81             :          */
      82        1325 :         mutex_lock(&c->lp_mutex);
      83             :         /*
      84             :          * Even though the TNC is clean, the LPT tree may have dirty nodes. For
      85             :          * example, this may happen if the budgeting subsystem invoked GC to
      86             :          * make some free space, and the GC found an LEB with only dirty and
      87             :          * free space. In this case GC would just change the lprops of this
      88             :          * LEB (by turning all space into free space) and unmap it.
      89             :          */
      90        2650 :         if (c->nroot && test_bit(DIRTY_CNODE, &c->nroot->flags)) {
      91        1220 :                 mutex_unlock(&c->lp_mutex);
      92        1220 :                 return 0;
      93             :         }
      94             : 
      95         105 :         ubifs_assert(c, atomic_long_read(&c->dirty_zn_cnt) == 0);
      96         105 :         ubifs_assert(c, c->dirty_pn_cnt == 0);
      97         105 :         ubifs_assert(c, c->dirty_nn_cnt == 0);
      98         105 :         mutex_unlock(&c->lp_mutex);
      99             : 
     100         105 :         return 1;
     101             : }
     102             : 
     103             : /**
     104             :  * do_commit - commit the journal.
     105             :  * @c: UBIFS file-system description object
     106             :  *
     107             :  * This function implements UBIFS commit. It has to be called with commit lock
     108             :  * locked. Returns zero in case of success and a negative error code in case of
     109             :  * failure.
     110             :  */
     111        3532 : static int do_commit(struct ubifs_info *c)
     112             : {
     113             :         int err, new_ltail_lnum, old_ltail_lnum, i;
     114             :         struct ubifs_zbranch zroot;
     115             :         struct ubifs_lp_stats lst;
     116             : 
     117        3532 :         dbg_cmt("start");
     118        3532 :         ubifs_assert(c, !c->ro_media && !c->ro_mount);
     119             : 
     120        3532 :         if (c->ro_error) {
     121             :                 err = -EROFS;
     122             :                 goto out_up;
     123             :         }
     124             : 
     125        3532 :         if (nothing_to_commit(c)) {
     126         105 :                 up_write(&c->commit_sem);
     127         105 :                 err = 0;
     128         105 :                 goto out_cancel;
     129             :         }
     130             : 
     131             :         /* Sync all write buffers (necessary for recovery) */
     132       10281 :         for (i = 0; i < c->jhead_cnt; i++) {
     133       10281 :                 err = ubifs_wbuf_sync(&c->jheads[i].wbuf);
     134       10281 :                 if (err)
     135             :                         goto out_up;
     136             :         }
     137             : 
     138        3427 :         c->cmt_no += 1;
     139        3427 :         err = ubifs_gc_start_commit(c);
     140        3427 :         if (err)
     141             :                 goto out_up;
     142        3427 :         err = dbg_check_lprops(c);
     143             :         if (err)
     144             :                 goto out_up;
     145        3427 :         err = ubifs_log_start_commit(c, &new_ltail_lnum);
     146        3427 :         if (err)
     147             :                 goto out_up;
     148        3427 :         err = ubifs_tnc_start_commit(c, &zroot);
     149        3427 :         if (err)
     150             :                 goto out_up;
     151        3427 :         err = ubifs_lpt_start_commit(c);
     152        3427 :         if (err)
     153             :                 goto out_up;
     154        3427 :         err = ubifs_orphan_start_commit(c);
     155        3427 :         if (err)
     156             :                 goto out_up;
     157             : 
     158        3427 :         ubifs_get_lp_stats(c, &lst);
     159             : 
     160        3427 :         up_write(&c->commit_sem);
     161             : 
     162        3427 :         err = ubifs_tnc_end_commit(c);
     163        3427 :         if (err)
     164             :                 goto out;
     165        3400 :         err = ubifs_lpt_end_commit(c);
     166        3400 :         if (err)
     167             :                 goto out;
     168        3398 :         err = ubifs_orphan_end_commit(c);
     169        3398 :         if (err)
     170             :                 goto out;
     171        3398 :         err = dbg_check_old_index(c, &zroot);
     172             :         if (err)
     173             :                 goto out;
     174             : 
     175        3398 :         c->mst_node->cmt_no      = cpu_to_le64(c->cmt_no);
     176        3398 :         c->mst_node->log_lnum    = cpu_to_le32(new_ltail_lnum);
     177        3398 :         c->mst_node->root_lnum   = cpu_to_le32(zroot.lnum);
     178        3398 :         c->mst_node->root_offs   = cpu_to_le32(zroot.offs);
     179        3398 :         c->mst_node->root_len    = cpu_to_le32(zroot.len);
     180        3398 :         c->mst_node->ihead_lnum  = cpu_to_le32(c->ihead_lnum);
     181        3398 :         c->mst_node->ihead_offs  = cpu_to_le32(c->ihead_offs);
     182        3398 :         c->mst_node->index_size  = cpu_to_le64(c->bi.old_idx_sz);
     183        3398 :         c->mst_node->lpt_lnum    = cpu_to_le32(c->lpt_lnum);
     184        3398 :         c->mst_node->lpt_offs    = cpu_to_le32(c->lpt_offs);
     185        3398 :         c->mst_node->nhead_lnum  = cpu_to_le32(c->nhead_lnum);
     186        3398 :         c->mst_node->nhead_offs  = cpu_to_le32(c->nhead_offs);
     187        3398 :         c->mst_node->ltab_lnum   = cpu_to_le32(c->ltab_lnum);
     188        3398 :         c->mst_node->ltab_offs   = cpu_to_le32(c->ltab_offs);
     189        3398 :         c->mst_node->lsave_lnum  = cpu_to_le32(c->lsave_lnum);
     190        3398 :         c->mst_node->lsave_offs  = cpu_to_le32(c->lsave_offs);
     191        3398 :         c->mst_node->lscan_lnum  = cpu_to_le32(c->lscan_lnum);
     192        3398 :         c->mst_node->empty_lebs  = cpu_to_le32(lst.empty_lebs);
     193        3398 :         c->mst_node->idx_lebs    = cpu_to_le32(lst.idx_lebs);
     194        3398 :         c->mst_node->total_free  = cpu_to_le64(lst.total_free);
     195        3398 :         c->mst_node->total_dirty = cpu_to_le64(lst.total_dirty);
     196        3398 :         c->mst_node->total_used  = cpu_to_le64(lst.total_used);
     197        3398 :         c->mst_node->total_dead  = cpu_to_le64(lst.total_dead);
     198        3398 :         c->mst_node->total_dark  = cpu_to_le64(lst.total_dark);
     199        3398 :         if (c->no_orphs)
     200        3398 :                 c->mst_node->flags |= cpu_to_le32(UBIFS_MST_NO_ORPHS);
     201             :         else
     202           0 :                 c->mst_node->flags &= ~cpu_to_le32(UBIFS_MST_NO_ORPHS);
     203             : 
     204        3398 :         old_ltail_lnum = c->ltail_lnum;
     205        3398 :         err = ubifs_log_end_commit(c, new_ltail_lnum);
     206        3398 :         if (err)
     207             :                 goto out;
     208             : 
     209        3398 :         err = ubifs_log_post_commit(c, old_ltail_lnum);
     210        3398 :         if (err)
     211             :                 goto out;
     212        3398 :         err = ubifs_gc_end_commit(c);
     213        3398 :         if (err)
     214             :                 goto out;
     215        3398 :         err = ubifs_lpt_post_commit(c);
     216        3398 :         if (err)
     217             :                 goto out;
     218             : 
     219        3398 : out_cancel:
     220        3503 :         spin_lock(&c->cs_lock);
     221        3503 :         c->cmt_state = COMMIT_RESTING;
     222        3503 :         dbg_cmt("commit end");
     223        3503 :         spin_unlock(&c->cs_lock);
     224        3503 :         return 0;
     225             : 
     226           0 : out_up:
     227           0 :         up_write(&c->commit_sem);
     228          58 : out:
     229          29 :         ubifs_err(c, "commit failed, error %d", err);
     230          29 :         spin_lock(&c->cs_lock);
     231          29 :         c->cmt_state = COMMIT_BROKEN;
     232          29 :         spin_unlock(&c->cs_lock);
     233          29 :         ubifs_ro_mode(c, err);
     234          29 :         return err;
     235             : }
     236             : 
     237             : /**
     238             :  * ubifs_commit_required - set commit state to "required".
     239             :  * @c: UBIFS file-system description object
     240             :  *
     241             :  * This function is called if a commit is required but cannot be done from the
     242             :  * calling function, so it is just flagged instead.
     243             :  */
     244           0 : void ubifs_commit_required(struct ubifs_info *c)
     245             : {
     246           0 :         spin_lock(&c->cs_lock);
     247           0 :         switch (c->cmt_state) {
     248           0 :         case COMMIT_RESTING:
     249             :         case COMMIT_BACKGROUND:
     250           0 :                 dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state),
     251             :                         dbg_cstate(COMMIT_REQUIRED));
     252           0 :                 c->cmt_state = COMMIT_REQUIRED;
     253           0 :                 break;
     254           0 :         case COMMIT_RUNNING_BACKGROUND:
     255           0 :                 dbg_cmt("old: %s, new: %s", dbg_cstate(c->cmt_state),
     256             :                         dbg_cstate(COMMIT_RUNNING_REQUIRED));
     257           0 :                 c->cmt_state = COMMIT_RUNNING_REQUIRED;
     258           0 :                 break;
     259             :         case COMMIT_REQUIRED:
     260             :         case COMMIT_RUNNING_REQUIRED:
     261             :         case COMMIT_BROKEN:
     262             :                 break;
     263             :         }
     264           0 :         spin_unlock(&c->cs_lock);
     265           0 : }
     266             : 
     267             : /**
     268             :  * ubifs_request_bg_commit - notify the background thread to do a commit.
     269             :  * @c: UBIFS file-system description object
     270             :  *
     271             :  * This function is called if the journal is full enough to make a commit
     272             :  * worthwhile, so background thread is kicked to start it.
     273             :  */
     274           0 : void ubifs_request_bg_commit(__unused struct ubifs_info *c)
     275             : {
     276           0 : }
     277             : 
     278             : /**
     279             :  * wait_for_commit - wait for commit.
     280             :  * @c: UBIFS file-system description object
     281             :  *
     282             :  * This function sleeps until the commit operation is no longer running.
     283             :  */
     284             : static int wait_for_commit(struct ubifs_info *c)
     285             : {
     286             :         /*
     287             :          * All commit operations are executed in synchronization context,
     288             :          * so it is impossible that more than one threads doing commit.
     289             :          */
     290           0 :         ubifs_assert(c, 0);
     291             :         return 0;
     292             : }
     293             : 
     294             : /**
     295             :  * ubifs_run_commit - run or wait for commit.
     296             :  * @c: UBIFS file-system description object
     297             :  *
     298             :  * This function runs commit and returns zero in case of success and a negative
     299             :  * error code in case of failure.
     300             :  */
     301        3532 : int ubifs_run_commit(struct ubifs_info *c)
     302             : {
     303        3532 :         int err = 0;
     304             : 
     305        3532 :         spin_lock(&c->cs_lock);
     306        3532 :         if (c->cmt_state == COMMIT_BROKEN) {
     307             :                 err = -EROFS;
     308             :                 goto out;
     309             :         }
     310             : 
     311        3532 :         if (c->cmt_state == COMMIT_RUNNING_BACKGROUND)
     312             :                 /*
     313             :                  * We set the commit state to 'running required' to indicate
     314             :                  * that we want it to complete as quickly as possible.
     315             :                  */
     316           0 :                 c->cmt_state = COMMIT_RUNNING_REQUIRED;
     317             : 
     318        3532 :         if (c->cmt_state == COMMIT_RUNNING_REQUIRED) {
     319           0 :                 spin_unlock(&c->cs_lock);
     320           0 :                 return wait_for_commit(c);
     321             :         }
     322        3532 :         spin_unlock(&c->cs_lock);
     323             : 
     324             :         /* Ok, the commit is indeed needed */
     325             : 
     326        3532 :         down_write(&c->commit_sem);
     327        3532 :         spin_lock(&c->cs_lock);
     328             :         /*
     329             :          * Since we unlocked 'c->cs_lock', the state may have changed, so
     330             :          * re-check it.
     331             :          */
     332        3532 :         if (c->cmt_state == COMMIT_BROKEN) {
     333           0 :                 err = -EROFS;
     334             :                 goto out_cmt_unlock;
     335             :         }
     336             : 
     337        3532 :         if (c->cmt_state == COMMIT_RUNNING_BACKGROUND)
     338           0 :                 c->cmt_state = COMMIT_RUNNING_REQUIRED;
     339             : 
     340        3532 :         if (c->cmt_state == COMMIT_RUNNING_REQUIRED) {
     341           0 :                 up_write(&c->commit_sem);
     342           0 :                 spin_unlock(&c->cs_lock);
     343           0 :                 return wait_for_commit(c);
     344             :         }
     345        3532 :         c->cmt_state = COMMIT_RUNNING_REQUIRED;
     346        3532 :         spin_unlock(&c->cs_lock);
     347             : 
     348        3532 :         err = do_commit(c);
     349        3532 :         return err;
     350             : 
     351           0 : out_cmt_unlock:
     352           0 :         up_write(&c->commit_sem);
     353           0 : out:
     354           0 :         spin_unlock(&c->cs_lock);
     355           0 :         return err;
     356             : }
     357             : 
     358             : /**
     359             :  * ubifs_gc_should_commit - determine if it is time for GC to run commit.
     360             :  * @c: UBIFS file-system description object
     361             :  *
     362             :  * This function is called by garbage collection to determine if commit should
     363             :  * be run. If commit state is @COMMIT_BACKGROUND, which means that the journal
     364             :  * is full enough to start commit, this function returns true. It is not
     365             :  * absolutely necessary to commit yet, but it feels like this should be better
     366             :  * then to keep doing GC. This function returns %1 if GC has to initiate commit
     367             :  * and %0 if not.
     368             :  */
     369           0 : int ubifs_gc_should_commit(struct ubifs_info *c)
     370             : {
     371           0 :         int ret = 0;
     372             : 
     373           0 :         spin_lock(&c->cs_lock);
     374           0 :         if (c->cmt_state == COMMIT_BACKGROUND) {
     375           0 :                 dbg_cmt("commit required now");
     376           0 :                 c->cmt_state = COMMIT_REQUIRED;
     377             :         } else
     378           0 :                 dbg_cmt("commit not requested");
     379           0 :         if (c->cmt_state == COMMIT_REQUIRED)
     380           0 :                 ret = 1;
     381           0 :         spin_unlock(&c->cs_lock);
     382           0 :         return ret;
     383             : }

Generated by: LCOV version 1.13