LCOV - code coverage report
Current view: top level - fs/btrfs - dev-replace.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 399 0.0 %
Date: 2014-04-16 Functions: 0 17 0.0 %
Branches: 0 177 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) STRATO AG 2012.  All rights reserved.
       3                 :            :  *
       4                 :            :  * This program is free software; you can redistribute it and/or
       5                 :            :  * modify it under the terms of the GNU General Public
       6                 :            :  * License v2 as published by the Free Software Foundation.
       7                 :            :  *
       8                 :            :  * This program is distributed in the hope that it will be useful,
       9                 :            :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      10                 :            :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      11                 :            :  * General Public License for more details.
      12                 :            :  *
      13                 :            :  * You should have received a copy of the GNU General Public
      14                 :            :  * License along with this program; if not, write to the
      15                 :            :  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
      16                 :            :  * Boston, MA 021110-1307, USA.
      17                 :            :  */
      18                 :            : #include <linux/sched.h>
      19                 :            : #include <linux/bio.h>
      20                 :            : #include <linux/slab.h>
      21                 :            : #include <linux/buffer_head.h>
      22                 :            : #include <linux/blkdev.h>
      23                 :            : #include <linux/random.h>
      24                 :            : #include <linux/iocontext.h>
      25                 :            : #include <linux/capability.h>
      26                 :            : #include <linux/kthread.h>
      27                 :            : #include <linux/math64.h>
      28                 :            : #include <asm/div64.h>
      29                 :            : #include "ctree.h"
      30                 :            : #include "extent_map.h"
      31                 :            : #include "disk-io.h"
      32                 :            : #include "transaction.h"
      33                 :            : #include "print-tree.h"
      34                 :            : #include "volumes.h"
      35                 :            : #include "async-thread.h"
      36                 :            : #include "check-integrity.h"
      37                 :            : #include "rcu-string.h"
      38                 :            : #include "dev-replace.h"
      39                 :            : 
      40                 :            : static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
      41                 :            :                                        int scrub_ret);
      42                 :            : static void btrfs_dev_replace_update_device_in_mapping_tree(
      43                 :            :                                                 struct btrfs_fs_info *fs_info,
      44                 :            :                                                 struct btrfs_device *srcdev,
      45                 :            :                                                 struct btrfs_device *tgtdev);
      46                 :            : static int btrfs_dev_replace_find_srcdev(struct btrfs_root *root, u64 srcdevid,
      47                 :            :                                          char *srcdev_name,
      48                 :            :                                          struct btrfs_device **device);
      49                 :            : static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info);
      50                 :            : static int btrfs_dev_replace_kthread(void *data);
      51                 :            : static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info);
      52                 :            : 
      53                 :            : 
      54                 :          0 : int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info)
      55                 :            : {
      56                 :            :         struct btrfs_key key;
      57                 :          0 :         struct btrfs_root *dev_root = fs_info->dev_root;
      58                 :            :         struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
      59                 :            :         struct extent_buffer *eb;
      60                 :            :         int slot;
      61                 :            :         int ret = 0;
      62                 :            :         struct btrfs_path *path = NULL;
      63                 :            :         int item_size;
      64                 :            :         struct btrfs_dev_replace_item *ptr;
      65                 :            :         u64 src_devid;
      66                 :            : 
      67                 :          0 :         path = btrfs_alloc_path();
      68         [ #  # ]:          0 :         if (!path) {
      69                 :            :                 ret = -ENOMEM;
      70                 :            :                 goto out;
      71                 :            :         }
      72                 :            : 
      73                 :          0 :         key.objectid = 0;
      74                 :          0 :         key.type = BTRFS_DEV_REPLACE_KEY;
      75                 :          0 :         key.offset = 0;
      76                 :          0 :         ret = btrfs_search_slot(NULL, dev_root, &key, path, 0, 0);
      77         [ #  # ]:          0 :         if (ret) {
      78                 :            : no_valid_dev_replace_entry_found:
      79                 :            :                 ret = 0;
      80                 :          0 :                 dev_replace->replace_state =
      81                 :            :                         BTRFS_DEV_REPLACE_ITEM_STATE_NEVER_STARTED;
      82                 :          0 :                 dev_replace->cont_reading_from_srcdev_mode =
      83                 :            :                     BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_ALWAYS;
      84                 :            :                 dev_replace->replace_state = 0;
      85                 :          0 :                 dev_replace->time_started = 0;
      86                 :          0 :                 dev_replace->time_stopped = 0;
      87                 :          0 :                 atomic64_set(&dev_replace->num_write_errors, 0);
      88                 :          0 :                 atomic64_set(&dev_replace->num_uncorrectable_read_errors, 0);
      89                 :          0 :                 dev_replace->cursor_left = 0;
      90                 :          0 :                 dev_replace->committed_cursor_left = 0;
      91                 :          0 :                 dev_replace->cursor_left_last_write_of_item = 0;
      92                 :          0 :                 dev_replace->cursor_right = 0;
      93                 :          0 :                 dev_replace->srcdev = NULL;
      94                 :          0 :                 dev_replace->tgtdev = NULL;
      95                 :          0 :                 dev_replace->is_valid = 0;
      96                 :          0 :                 dev_replace->item_needs_writeback = 0;
      97                 :          0 :                 goto out;
      98                 :            :         }
      99                 :          0 :         slot = path->slots[0];
     100                 :          0 :         eb = path->nodes[0];
     101                 :            :         item_size = btrfs_item_size_nr(eb, slot);
     102                 :          0 :         ptr = btrfs_item_ptr(eb, slot, struct btrfs_dev_replace_item);
     103                 :            : 
     104         [ #  # ]:          0 :         if (item_size != sizeof(struct btrfs_dev_replace_item)) {
     105                 :          0 :                 btrfs_warn(fs_info,
     106                 :            :                         "dev_replace entry found has unexpected size, ignore entry");
     107                 :          0 :                 goto no_valid_dev_replace_entry_found;
     108                 :            :         }
     109                 :            : 
     110                 :            :         src_devid = btrfs_dev_replace_src_devid(eb, ptr);
     111                 :          0 :         dev_replace->cont_reading_from_srcdev_mode =
     112                 :            :                 btrfs_dev_replace_cont_reading_from_srcdev_mode(eb, ptr);
     113                 :          0 :         dev_replace->replace_state = btrfs_dev_replace_replace_state(eb, ptr);
     114                 :          0 :         dev_replace->time_started = btrfs_dev_replace_time_started(eb, ptr);
     115                 :          0 :         dev_replace->time_stopped =
     116                 :            :                 btrfs_dev_replace_time_stopped(eb, ptr);
     117                 :          0 :         atomic64_set(&dev_replace->num_write_errors,
     118                 :            :                      btrfs_dev_replace_num_write_errors(eb, ptr));
     119                 :          0 :         atomic64_set(&dev_replace->num_uncorrectable_read_errors,
     120                 :            :                      btrfs_dev_replace_num_uncorrectable_read_errors(eb, ptr));
     121                 :          0 :         dev_replace->cursor_left = btrfs_dev_replace_cursor_left(eb, ptr);
     122                 :          0 :         dev_replace->committed_cursor_left = dev_replace->cursor_left;
     123                 :          0 :         dev_replace->cursor_left_last_write_of_item = dev_replace->cursor_left;
     124                 :          0 :         dev_replace->cursor_right = btrfs_dev_replace_cursor_right(eb, ptr);
     125                 :          0 :         dev_replace->is_valid = 1;
     126                 :            : 
     127                 :          0 :         dev_replace->item_needs_writeback = 0;
     128 [ #  # ][ #  # ]:          0 :         switch (dev_replace->replace_state) {
                 [ #  # ]
     129                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
     130                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
     131                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
     132                 :          0 :                 dev_replace->srcdev = NULL;
     133                 :          0 :                 dev_replace->tgtdev = NULL;
     134                 :          0 :                 break;
     135                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
     136                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
     137                 :          0 :                 dev_replace->srcdev = btrfs_find_device(fs_info, src_devid,
     138                 :            :                                                         NULL, NULL);
     139                 :          0 :                 dev_replace->tgtdev = btrfs_find_device(fs_info,
     140                 :            :                                                         BTRFS_DEV_REPLACE_DEVID,
     141                 :            :                                                         NULL, NULL);
     142                 :            :                 /*
     143                 :            :                  * allow 'btrfs dev replace_cancel' if src/tgt device is
     144                 :            :                  * missing
     145                 :            :                  */
     146 [ #  # ][ #  # ]:          0 :                 if (!dev_replace->srcdev &&
     147                 :          0 :                     !btrfs_test_opt(dev_root, DEGRADED)) {
     148                 :            :                         ret = -EIO;
     149                 :          0 :                         btrfs_warn(fs_info,
     150                 :            :                            "cannot mount because device replace operation is ongoing and");
     151                 :          0 :                         btrfs_warn(fs_info,
     152                 :            :                            "srcdev (devid %llu) is missing, need to run 'btrfs dev scan'?",
     153                 :            :                            src_devid);
     154                 :            :                 }
     155 [ #  # ][ #  # ]:          0 :                 if (!dev_replace->tgtdev &&
     156                 :          0 :                     !btrfs_test_opt(dev_root, DEGRADED)) {
     157                 :            :                         ret = -EIO;
     158                 :          0 :                         btrfs_warn(fs_info,
     159                 :            :                            "cannot mount because device replace operation is ongoing and");
     160                 :          0 :                         btrfs_warn(fs_info,
     161                 :            :                            "tgtdev (devid %llu) is missing, need to run 'btrfs dev scan'?",
     162                 :            :                                 BTRFS_DEV_REPLACE_DEVID);
     163                 :            :                 }
     164         [ #  # ]:          0 :                 if (dev_replace->tgtdev) {
     165         [ #  # ]:          0 :                         if (dev_replace->srcdev) {
     166                 :          0 :                                 dev_replace->tgtdev->total_bytes =
     167                 :          0 :                                         dev_replace->srcdev->total_bytes;
     168                 :          0 :                                 dev_replace->tgtdev->disk_total_bytes =
     169                 :          0 :                                         dev_replace->srcdev->disk_total_bytes;
     170                 :          0 :                                 dev_replace->tgtdev->bytes_used =
     171                 :          0 :                                         dev_replace->srcdev->bytes_used;
     172                 :            :                         }
     173                 :          0 :                         dev_replace->tgtdev->is_tgtdev_for_dev_replace = 1;
     174                 :          0 :                         btrfs_init_dev_replace_tgtdev_for_resume(fs_info,
     175                 :            :                                 dev_replace->tgtdev);
     176                 :            :                 }
     177                 :            :                 break;
     178                 :            :         }
     179                 :            : 
     180                 :            : out:
     181         [ #  # ]:          0 :         if (path)
     182                 :          0 :                 btrfs_free_path(path);
     183                 :          0 :         return ret;
     184                 :            : }
     185                 :            : 
     186                 :            : /*
     187                 :            :  * called from commit_transaction. Writes changed device replace state to
     188                 :            :  * disk.
     189                 :            :  */
     190                 :          0 : int btrfs_run_dev_replace(struct btrfs_trans_handle *trans,
     191                 :            :                           struct btrfs_fs_info *fs_info)
     192                 :            : {
     193                 :            :         int ret;
     194                 :          0 :         struct btrfs_root *dev_root = fs_info->dev_root;
     195                 :            :         struct btrfs_path *path;
     196                 :            :         struct btrfs_key key;
     197                 :            :         struct extent_buffer *eb;
     198                 :            :         struct btrfs_dev_replace_item *ptr;
     199                 :          0 :         struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
     200                 :            : 
     201                 :          0 :         btrfs_dev_replace_lock(dev_replace);
     202 [ #  # ][ #  # ]:          0 :         if (!dev_replace->is_valid ||
     203                 :          0 :             !dev_replace->item_needs_writeback) {
     204                 :          0 :                 btrfs_dev_replace_unlock(dev_replace);
     205                 :          0 :                 return 0;
     206                 :            :         }
     207                 :          0 :         btrfs_dev_replace_unlock(dev_replace);
     208                 :            : 
     209                 :          0 :         key.objectid = 0;
     210                 :          0 :         key.type = BTRFS_DEV_REPLACE_KEY;
     211                 :          0 :         key.offset = 0;
     212                 :            : 
     213                 :          0 :         path = btrfs_alloc_path();
     214         [ #  # ]:          0 :         if (!path) {
     215                 :            :                 ret = -ENOMEM;
     216                 :            :                 goto out;
     217                 :            :         }
     218                 :          0 :         ret = btrfs_search_slot(trans, dev_root, &key, path, -1, 1);
     219         [ #  # ]:          0 :         if (ret < 0) {
     220                 :          0 :                 btrfs_warn(fs_info, "error %d while searching for dev_replace item!",
     221                 :            :                         ret);
     222                 :          0 :                 goto out;
     223                 :            :         }
     224                 :            : 
     225   [ #  #  #  # ]:          0 :         if (ret == 0 &&
     226                 :          0 :             btrfs_item_size_nr(path->nodes[0], path->slots[0]) < sizeof(*ptr)) {
     227                 :            :                 /*
     228                 :            :                  * need to delete old one and insert a new one.
     229                 :            :                  * Since no attempt is made to recover any old state, if the
     230                 :            :                  * dev_replace state is 'running', the data on the target
     231                 :            :                  * drive is lost.
     232                 :            :                  * It would be possible to recover the state: just make sure
     233                 :            :                  * that the beginning of the item is never changed and always
     234                 :            :                  * contains all the essential information. Then read this
     235                 :            :                  * minimal set of information and use it as a base for the
     236                 :            :                  * new state.
     237                 :            :                  */
     238                 :            :                 ret = btrfs_del_item(trans, dev_root, path);
     239         [ #  # ]:          0 :                 if (ret != 0) {
     240                 :          0 :                         btrfs_warn(fs_info, "delete too small dev_replace item failed %d!",
     241                 :            :                                 ret);
     242                 :          0 :                         goto out;
     243                 :            :                 }
     244                 :            :                 ret = 1;
     245                 :            :         }
     246                 :            : 
     247         [ #  # ]:          0 :         if (ret == 1) {
     248                 :            :                 /* need to insert a new item */
     249                 :          0 :                 btrfs_release_path(path);
     250                 :            :                 ret = btrfs_insert_empty_item(trans, dev_root, path,
     251                 :            :                                               &key, sizeof(*ptr));
     252         [ #  # ]:          0 :                 if (ret < 0) {
     253                 :          0 :                         btrfs_warn(fs_info, "insert dev_replace item failed %d!",
     254                 :            :                                 ret);
     255                 :          0 :                         goto out;
     256                 :            :                 }
     257                 :            :         }
     258                 :            : 
     259                 :          0 :         eb = path->nodes[0];
     260                 :          0 :         ptr = btrfs_item_ptr(eb, path->slots[0],
     261                 :            :                              struct btrfs_dev_replace_item);
     262                 :            : 
     263                 :          0 :         btrfs_dev_replace_lock(dev_replace);
     264         [ #  # ]:          0 :         if (dev_replace->srcdev)
     265                 :          0 :                 btrfs_set_dev_replace_src_devid(eb, ptr,
     266                 :            :                         dev_replace->srcdev->devid);
     267                 :            :         else
     268                 :            :                 btrfs_set_dev_replace_src_devid(eb, ptr, (u64)-1);
     269                 :          0 :         btrfs_set_dev_replace_cont_reading_from_srcdev_mode(eb, ptr,
     270                 :            :                 dev_replace->cont_reading_from_srcdev_mode);
     271                 :          0 :         btrfs_set_dev_replace_replace_state(eb, ptr,
     272                 :            :                 dev_replace->replace_state);
     273                 :          0 :         btrfs_set_dev_replace_time_started(eb, ptr, dev_replace->time_started);
     274                 :          0 :         btrfs_set_dev_replace_time_stopped(eb, ptr, dev_replace->time_stopped);
     275                 :          0 :         btrfs_set_dev_replace_num_write_errors(eb, ptr,
     276                 :          0 :                 atomic64_read(&dev_replace->num_write_errors));
     277                 :          0 :         btrfs_set_dev_replace_num_uncorrectable_read_errors(eb, ptr,
     278                 :          0 :                 atomic64_read(&dev_replace->num_uncorrectable_read_errors));
     279                 :          0 :         dev_replace->cursor_left_last_write_of_item =
     280                 :          0 :                 dev_replace->cursor_left;
     281                 :            :         btrfs_set_dev_replace_cursor_left(eb, ptr,
     282                 :            :                 dev_replace->cursor_left_last_write_of_item);
     283                 :          0 :         btrfs_set_dev_replace_cursor_right(eb, ptr,
     284                 :            :                 dev_replace->cursor_right);
     285                 :          0 :         dev_replace->item_needs_writeback = 0;
     286                 :          0 :         btrfs_dev_replace_unlock(dev_replace);
     287                 :            : 
     288                 :          0 :         btrfs_mark_buffer_dirty(eb);
     289                 :            : 
     290                 :            : out:
     291                 :          0 :         btrfs_free_path(path);
     292                 :            : 
     293                 :          0 :         return ret;
     294                 :            : }
     295                 :            : 
     296                 :          0 : void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info)
     297                 :            : {
     298                 :            :         struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
     299                 :            : 
     300                 :          0 :         dev_replace->committed_cursor_left =
     301                 :          0 :                 dev_replace->cursor_left_last_write_of_item;
     302                 :          0 : }
     303                 :            : 
     304                 :          0 : int btrfs_dev_replace_start(struct btrfs_root *root,
     305                 :            :                             struct btrfs_ioctl_dev_replace_args *args)
     306                 :            : {
     307                 :            :         struct btrfs_trans_handle *trans;
     308                 :          0 :         struct btrfs_fs_info *fs_info = root->fs_info;
     309                 :          0 :         struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
     310                 :            :         int ret;
     311                 :          0 :         struct btrfs_device *tgt_device = NULL;
     312                 :          0 :         struct btrfs_device *src_device = NULL;
     313                 :            : 
     314         [ #  # ]:          0 :         if (btrfs_fs_incompat(fs_info, RAID56)) {
     315                 :          0 :                 btrfs_warn(fs_info, "dev_replace cannot yet handle RAID5/RAID6");
     316                 :          0 :                 return -EINVAL;
     317                 :            :         }
     318                 :            : 
     319         [ #  # ]:          0 :         switch (args->start.cont_reading_from_srcdev_mode) {
     320                 :            :         case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS:
     321                 :            :         case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID:
     322                 :            :                 break;
     323                 :            :         default:
     324                 :            :                 return -EINVAL;
     325                 :            :         }
     326                 :            : 
     327 [ #  # ][ #  # ]:          0 :         if ((args->start.srcdevid == 0 && args->start.srcdev_name[0] == '\0') ||
                 [ #  # ]
     328                 :          0 :             args->start.tgtdev_name[0] == '\0')
     329                 :            :                 return -EINVAL;
     330                 :            : 
     331                 :          0 :         mutex_lock(&fs_info->volume_mutex);
     332                 :          0 :         ret = btrfs_init_dev_replace_tgtdev(root, args->start.tgtdev_name,
     333                 :            :                                             &tgt_device);
     334         [ #  # ]:          0 :         if (ret) {
     335                 :          0 :                 btrfs_err(fs_info, "target device %s is invalid!",
     336                 :            :                        args->start.tgtdev_name);
     337                 :          0 :                 mutex_unlock(&fs_info->volume_mutex);
     338                 :          0 :                 return -EINVAL;
     339                 :            :         }
     340                 :            : 
     341                 :          0 :         ret = btrfs_dev_replace_find_srcdev(root, args->start.srcdevid,
     342                 :          0 :                                             args->start.srcdev_name,
     343                 :            :                                             &src_device);
     344                 :          0 :         mutex_unlock(&fs_info->volume_mutex);
     345         [ #  # ]:          0 :         if (ret) {
     346                 :            :                 ret = -EINVAL;
     347                 :            :                 goto leave_no_lock;
     348                 :            :         }
     349                 :            : 
     350         [ #  # ]:          0 :         if (tgt_device->total_bytes < src_device->total_bytes) {
     351                 :          0 :                 btrfs_err(fs_info, "target device is smaller than source device!");
     352                 :            :                 ret = -EINVAL;
     353                 :          0 :                 goto leave_no_lock;
     354                 :            :         }
     355                 :            : 
     356                 :          0 :         btrfs_dev_replace_lock(dev_replace);
     357         [ #  # ]:          0 :         switch (dev_replace->replace_state) {
     358                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
     359                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
     360                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
     361                 :            :                 break;
     362                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
     363                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
     364                 :          0 :                 args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED;
     365                 :          0 :                 goto leave;
     366                 :            :         }
     367                 :            : 
     368                 :          0 :         dev_replace->cont_reading_from_srcdev_mode =
     369                 :          0 :                 args->start.cont_reading_from_srcdev_mode;
     370         [ #  # ]:          0 :         WARN_ON(!src_device);
     371                 :          0 :         dev_replace->srcdev = src_device;
     372         [ #  # ]:          0 :         WARN_ON(!tgt_device);
     373                 :          0 :         dev_replace->tgtdev = tgt_device;
     374                 :            : 
     375         [ #  # ]:          0 :         printk_in_rcu(KERN_INFO
     376                 :            :                       "BTRFS: dev_replace from %s (devid %llu) to %s started\n",
     377                 :            :                       src_device->missing ? "<missing disk>" :
     378                 :            :                         rcu_str_deref(src_device->name),
     379                 :            :                       src_device->devid,
     380                 :            :                       rcu_str_deref(tgt_device->name));
     381                 :            : 
     382                 :          0 :         tgt_device->total_bytes = src_device->total_bytes;
     383                 :          0 :         tgt_device->disk_total_bytes = src_device->disk_total_bytes;
     384                 :          0 :         tgt_device->bytes_used = src_device->bytes_used;
     385                 :            : 
     386                 :            :         /*
     387                 :            :          * from now on, the writes to the srcdev are all duplicated to
     388                 :            :          * go to the tgtdev as well (refer to btrfs_map_block()).
     389                 :            :          */
     390                 :          0 :         dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED;
     391                 :          0 :         dev_replace->time_started = get_seconds();
     392                 :          0 :         dev_replace->cursor_left = 0;
     393                 :          0 :         dev_replace->committed_cursor_left = 0;
     394                 :          0 :         dev_replace->cursor_left_last_write_of_item = 0;
     395                 :          0 :         dev_replace->cursor_right = 0;
     396                 :          0 :         dev_replace->is_valid = 1;
     397                 :          0 :         dev_replace->item_needs_writeback = 1;
     398                 :          0 :         args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
     399                 :          0 :         btrfs_dev_replace_unlock(dev_replace);
     400                 :            : 
     401                 :          0 :         btrfs_wait_ordered_roots(root->fs_info, -1);
     402                 :            : 
     403                 :            :         /* force writing the updated state information to disk */
     404                 :          0 :         trans = btrfs_start_transaction(root, 0);
     405         [ #  # ]:          0 :         if (IS_ERR(trans)) {
     406                 :            :                 ret = PTR_ERR(trans);
     407                 :          0 :                 btrfs_dev_replace_lock(dev_replace);
     408                 :          0 :                 goto leave;
     409                 :            :         }
     410                 :            : 
     411                 :          0 :         ret = btrfs_commit_transaction(trans, root);
     412         [ #  # ]:          0 :         WARN_ON(ret);
     413                 :            : 
     414                 :            :         /* the disk copy procedure reuses the scrub code */
     415                 :          0 :         ret = btrfs_scrub_dev(fs_info, src_device->devid, 0,
     416                 :            :                               src_device->total_bytes,
     417                 :            :                               &dev_replace->scrub_progress, 0, 1);
     418                 :            : 
     419                 :          0 :         ret = btrfs_dev_replace_finishing(root->fs_info, ret);
     420         [ #  # ]:          0 :         WARN_ON(ret);
     421                 :            : 
     422                 :            :         return 0;
     423                 :            : 
     424                 :            : leave:
     425                 :          0 :         dev_replace->srcdev = NULL;
     426                 :          0 :         dev_replace->tgtdev = NULL;
     427                 :          0 :         btrfs_dev_replace_unlock(dev_replace);
     428                 :            : leave_no_lock:
     429         [ #  # ]:          0 :         if (tgt_device)
     430                 :          0 :                 btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device);
     431                 :          0 :         return ret;
     432                 :            : }
     433                 :            : 
     434                 :          0 : static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
     435                 :            :                                        int scrub_ret)
     436                 :            : {
     437                 :          0 :         struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
     438                 :            :         struct btrfs_device *tgt_device;
     439                 :            :         struct btrfs_device *src_device;
     440                 :          0 :         struct btrfs_root *root = fs_info->tree_root;
     441                 :            :         u8 uuid_tmp[BTRFS_UUID_SIZE];
     442                 :            :         struct btrfs_trans_handle *trans;
     443                 :            :         int ret = 0;
     444                 :            : 
     445                 :            :         /* don't allow cancel or unmount to disturb the finishing procedure */
     446                 :          0 :         mutex_lock(&dev_replace->lock_finishing_cancel_unmount);
     447                 :            : 
     448                 :          0 :         btrfs_dev_replace_lock(dev_replace);
     449                 :            :         /* was the operation canceled, or is it finished? */
     450         [ #  # ]:          0 :         if (dev_replace->replace_state !=
     451                 :            :             BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED) {
     452                 :          0 :                 btrfs_dev_replace_unlock(dev_replace);
     453                 :          0 :                 mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
     454                 :          0 :                 return 0;
     455                 :            :         }
     456                 :            : 
     457                 :          0 :         tgt_device = dev_replace->tgtdev;
     458                 :          0 :         src_device = dev_replace->srcdev;
     459                 :          0 :         btrfs_dev_replace_unlock(dev_replace);
     460                 :            : 
     461                 :            :         /* replace old device with new one in mapping tree */
     462         [ #  # ]:          0 :         if (!scrub_ret)
     463                 :          0 :                 btrfs_dev_replace_update_device_in_mapping_tree(fs_info,
     464                 :            :                                                                 src_device,
     465                 :            :                                                                 tgt_device);
     466                 :            : 
     467                 :            :         /*
     468                 :            :          * flush all outstanding I/O and inode extent mappings before the
     469                 :            :          * copy operation is declared as being finished
     470                 :            :          */
     471                 :          0 :         ret = btrfs_start_delalloc_roots(root->fs_info, 0);
     472         [ #  # ]:          0 :         if (ret) {
     473                 :          0 :                 mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
     474                 :          0 :                 return ret;
     475                 :            :         }
     476                 :          0 :         btrfs_wait_ordered_roots(root->fs_info, -1);
     477                 :            : 
     478                 :          0 :         trans = btrfs_start_transaction(root, 0);
     479         [ #  # ]:          0 :         if (IS_ERR(trans)) {
     480                 :          0 :                 mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
     481                 :          0 :                 return PTR_ERR(trans);
     482                 :            :         }
     483                 :          0 :         ret = btrfs_commit_transaction(trans, root);
     484         [ #  # ]:          0 :         WARN_ON(ret);
     485                 :            : 
     486                 :            :         /* keep away write_all_supers() during the finishing procedure */
     487                 :          0 :         mutex_lock(&root->fs_info->fs_devices->device_list_mutex);
     488                 :          0 :         btrfs_dev_replace_lock(dev_replace);
     489         [ #  # ]:          0 :         dev_replace->replace_state =
     490                 :            :                 scrub_ret ? BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED
     491                 :            :                           : BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED;
     492                 :          0 :         dev_replace->tgtdev = NULL;
     493                 :          0 :         dev_replace->srcdev = NULL;
     494                 :          0 :         dev_replace->time_stopped = get_seconds();
     495                 :          0 :         dev_replace->item_needs_writeback = 1;
     496                 :            : 
     497         [ #  # ]:          0 :         if (scrub_ret) {
     498         [ #  # ]:          0 :                 printk_in_rcu(KERN_ERR
     499                 :            :                               "BTRFS: btrfs_scrub_dev(%s, %llu, %s) failed %d\n",
     500                 :            :                               src_device->missing ? "<missing disk>" :
     501                 :            :                                 rcu_str_deref(src_device->name),
     502                 :            :                               src_device->devid,
     503                 :            :                               rcu_str_deref(tgt_device->name), scrub_ret);
     504                 :          0 :                 btrfs_dev_replace_unlock(dev_replace);
     505                 :          0 :                 mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
     506         [ #  # ]:          0 :                 if (tgt_device)
     507                 :          0 :                         btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device);
     508                 :          0 :                 mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
     509                 :            : 
     510                 :          0 :                 return 0;
     511                 :            :         }
     512                 :            : 
     513         [ #  # ]:          0 :         printk_in_rcu(KERN_INFO
     514                 :            :                       "BTRFS: dev_replace from %s (devid %llu) to %s) finished\n",
     515                 :            :                       src_device->missing ? "<missing disk>" :
     516                 :            :                         rcu_str_deref(src_device->name),
     517                 :            :                       src_device->devid,
     518                 :            :                       rcu_str_deref(tgt_device->name));
     519                 :          0 :         tgt_device->is_tgtdev_for_dev_replace = 0;
     520                 :          0 :         tgt_device->devid = src_device->devid;
     521                 :          0 :         src_device->devid = BTRFS_DEV_REPLACE_DEVID;
     522                 :          0 :         tgt_device->bytes_used = src_device->bytes_used;
     523                 :          0 :         memcpy(uuid_tmp, tgt_device->uuid, sizeof(uuid_tmp));
     524                 :          0 :         memcpy(tgt_device->uuid, src_device->uuid, sizeof(tgt_device->uuid));
     525                 :          0 :         memcpy(src_device->uuid, uuid_tmp, sizeof(src_device->uuid));
     526                 :          0 :         tgt_device->total_bytes = src_device->total_bytes;
     527                 :          0 :         tgt_device->disk_total_bytes = src_device->disk_total_bytes;
     528                 :          0 :         tgt_device->bytes_used = src_device->bytes_used;
     529         [ #  # ]:          0 :         if (fs_info->sb->s_bdev == src_device->bdev)
     530                 :          0 :                 fs_info->sb->s_bdev = tgt_device->bdev;
     531         [ #  # ]:          0 :         if (fs_info->fs_devices->latest_bdev == src_device->bdev)
     532                 :          0 :                 fs_info->fs_devices->latest_bdev = tgt_device->bdev;
     533                 :          0 :         list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list);
     534                 :            : 
     535                 :          0 :         btrfs_rm_dev_replace_srcdev(fs_info, src_device);
     536                 :            : 
     537                 :            :         /*
     538                 :            :          * this is again a consistent state where no dev_replace procedure
     539                 :            :          * is running, the target device is part of the filesystem, the
     540                 :            :          * source device is not part of the filesystem anymore and its 1st
     541                 :            :          * superblock is scratched out so that it is no longer marked to
     542                 :            :          * belong to this filesystem.
     543                 :            :          */
     544                 :          0 :         btrfs_dev_replace_unlock(dev_replace);
     545                 :          0 :         mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
     546                 :            : 
     547                 :            :         /* write back the superblocks */
     548                 :          0 :         trans = btrfs_start_transaction(root, 0);
     549         [ #  # ]:          0 :         if (!IS_ERR(trans))
     550                 :          0 :                 btrfs_commit_transaction(trans, root);
     551                 :            : 
     552                 :          0 :         mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
     553                 :            : 
     554                 :          0 :         return 0;
     555                 :            : }
     556                 :            : 
     557                 :          0 : static void btrfs_dev_replace_update_device_in_mapping_tree(
     558                 :            :                                                 struct btrfs_fs_info *fs_info,
     559                 :            :                                                 struct btrfs_device *srcdev,
     560                 :            :                                                 struct btrfs_device *tgtdev)
     561                 :            : {
     562                 :          0 :         struct extent_map_tree *em_tree = &fs_info->mapping_tree.map_tree;
     563                 :            :         struct extent_map *em;
     564                 :            :         struct map_lookup *map;
     565                 :            :         u64 start = 0;
     566                 :            :         int i;
     567                 :            : 
     568                 :          0 :         write_lock(&em_tree->lock);
     569                 :            :         do {
     570                 :          0 :                 em = lookup_extent_mapping(em_tree, start, (u64)-1);
     571         [ #  # ]:          0 :                 if (!em)
     572                 :            :                         break;
     573                 :          0 :                 map = (struct map_lookup *)em->bdev;
     574         [ #  # ]:          0 :                 for (i = 0; i < map->num_stripes; i++)
     575         [ #  # ]:          0 :                         if (srcdev == map->stripes[i].dev)
     576                 :          0 :                                 map->stripes[i].dev = tgtdev;
     577                 :          0 :                 start = em->start + em->len;
     578                 :          0 :                 free_extent_map(em);
     579         [ #  # ]:          0 :         } while (start);
     580                 :            :         write_unlock(&em_tree->lock);
     581                 :          0 : }
     582                 :            : 
     583                 :          0 : static int btrfs_dev_replace_find_srcdev(struct btrfs_root *root, u64 srcdevid,
     584                 :            :                                          char *srcdev_name,
     585                 :            :                                          struct btrfs_device **device)
     586                 :            : {
     587                 :            :         int ret;
     588                 :            : 
     589         [ #  # ]:          0 :         if (srcdevid) {
     590                 :            :                 ret = 0;
     591                 :          0 :                 *device = btrfs_find_device(root->fs_info, srcdevid, NULL,
     592                 :            :                                             NULL);
     593         [ #  # ]:          0 :                 if (!*device)
     594                 :            :                         ret = -ENOENT;
     595                 :            :         } else {
     596                 :          0 :                 ret = btrfs_find_device_missing_or_by_path(root, srcdev_name,
     597                 :            :                                                            device);
     598                 :            :         }
     599                 :          0 :         return ret;
     600                 :            : }
     601                 :            : 
     602                 :          0 : void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info,
     603                 :            :                               struct btrfs_ioctl_dev_replace_args *args)
     604                 :            : {
     605                 :          0 :         struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
     606                 :            : 
     607                 :          0 :         btrfs_dev_replace_lock(dev_replace);
     608                 :            :         /* even if !dev_replace_is_valid, the values are good enough for
     609                 :            :          * the replace_status ioctl */
     610                 :          0 :         args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
     611                 :          0 :         args->status.replace_state = dev_replace->replace_state;
     612                 :          0 :         args->status.time_started = dev_replace->time_started;
     613                 :          0 :         args->status.time_stopped = dev_replace->time_stopped;
     614                 :          0 :         args->status.num_write_errors =
     615                 :          0 :                 atomic64_read(&dev_replace->num_write_errors);
     616                 :          0 :         args->status.num_uncorrectable_read_errors =
     617                 :          0 :                 atomic64_read(&dev_replace->num_uncorrectable_read_errors);
     618   [ #  #  #  # ]:          0 :         switch (dev_replace->replace_state) {
     619                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
     620                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
     621                 :          0 :                 args->status.progress_1000 = 0;
     622                 :          0 :                 break;
     623                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
     624                 :          0 :                 args->status.progress_1000 = 1000;
     625                 :          0 :                 break;
     626                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
     627                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
     628                 :          0 :                 args->status.progress_1000 = div64_u64(dev_replace->cursor_left,
     629                 :          0 :                         div64_u64(dev_replace->srcdev->total_bytes, 1000));
     630                 :          0 :                 break;
     631                 :            :         }
     632                 :          0 :         btrfs_dev_replace_unlock(dev_replace);
     633                 :          0 : }
     634                 :            : 
     635                 :          0 : int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info,
     636                 :            :                              struct btrfs_ioctl_dev_replace_args *args)
     637                 :            : {
     638                 :          0 :         args->result = __btrfs_dev_replace_cancel(fs_info);
     639                 :          0 :         return 0;
     640                 :            : }
     641                 :            : 
     642                 :          0 : static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info)
     643                 :            : {
     644                 :          0 :         struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
     645                 :            :         struct btrfs_device *tgt_device = NULL;
     646                 :            :         struct btrfs_trans_handle *trans;
     647                 :          0 :         struct btrfs_root *root = fs_info->tree_root;
     648                 :            :         u64 result;
     649                 :            :         int ret;
     650                 :            : 
     651         [ #  # ]:          0 :         if (fs_info->sb->s_flags & MS_RDONLY)
     652                 :            :                 return -EROFS;
     653                 :            : 
     654                 :          0 :         mutex_lock(&dev_replace->lock_finishing_cancel_unmount);
     655                 :          0 :         btrfs_dev_replace_lock(dev_replace);
     656 [ #  # ][ #  # ]:          0 :         switch (dev_replace->replace_state) {
                 [ #  # ]
     657                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
     658                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
     659                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
     660                 :            :                 result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED;
     661                 :          0 :                 btrfs_dev_replace_unlock(dev_replace);
     662                 :          0 :                 goto leave;
     663                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
     664                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
     665                 :            :                 result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR;
     666                 :          0 :                 tgt_device = dev_replace->tgtdev;
     667                 :          0 :                 dev_replace->tgtdev = NULL;
     668                 :          0 :                 dev_replace->srcdev = NULL;
     669                 :          0 :                 break;
     670                 :            :         }
     671                 :          0 :         dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED;
     672                 :          0 :         dev_replace->time_stopped = get_seconds();
     673                 :          0 :         dev_replace->item_needs_writeback = 1;
     674                 :          0 :         btrfs_dev_replace_unlock(dev_replace);
     675                 :          0 :         btrfs_scrub_cancel(fs_info);
     676                 :            : 
     677                 :          0 :         trans = btrfs_start_transaction(root, 0);
     678         [ #  # ]:          0 :         if (IS_ERR(trans)) {
     679                 :          0 :                 mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
     680                 :          0 :                 return PTR_ERR(trans);
     681                 :            :         }
     682                 :          0 :         ret = btrfs_commit_transaction(trans, root);
     683         [ #  # ]:          0 :         WARN_ON(ret);
     684         [ #  # ]:          0 :         if (tgt_device)
     685                 :          0 :                 btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device);
     686                 :            : 
     687                 :            : leave:
     688                 :          0 :         mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
     689                 :          0 :         return result;
     690                 :            : }
     691                 :            : 
     692                 :          0 : void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info)
     693                 :            : {
     694                 :          0 :         struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
     695                 :            : 
     696                 :          0 :         mutex_lock(&dev_replace->lock_finishing_cancel_unmount);
     697                 :          0 :         btrfs_dev_replace_lock(dev_replace);
     698         [ #  # ]:          0 :         switch (dev_replace->replace_state) {
     699                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
     700                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
     701                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
     702                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
     703                 :            :                 break;
     704                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
     705                 :          0 :                 dev_replace->replace_state =
     706                 :            :                         BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED;
     707                 :          0 :                 dev_replace->time_stopped = get_seconds();
     708                 :          0 :                 dev_replace->item_needs_writeback = 1;
     709                 :          0 :                 btrfs_info(fs_info, "suspending dev_replace for unmount");
     710                 :          0 :                 break;
     711                 :            :         }
     712                 :            : 
     713                 :          0 :         btrfs_dev_replace_unlock(dev_replace);
     714                 :          0 :         mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
     715                 :          0 : }
     716                 :            : 
     717                 :            : /* resume dev_replace procedure that was interrupted by unmount */
     718                 :          0 : int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info)
     719                 :            : {
     720                 :            :         struct task_struct *task;
     721                 :          0 :         struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
     722                 :            : 
     723                 :          0 :         btrfs_dev_replace_lock(dev_replace);
     724      [ #  #  # ]:          0 :         switch (dev_replace->replace_state) {
     725                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
     726                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
     727                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
     728                 :          0 :                 btrfs_dev_replace_unlock(dev_replace);
     729                 :          0 :                 return 0;
     730                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
     731                 :            :                 break;
     732                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
     733                 :          0 :                 dev_replace->replace_state =
     734                 :            :                         BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED;
     735                 :          0 :                 break;
     736                 :            :         }
     737 [ #  # ][ #  # ]:          0 :         if (!dev_replace->tgtdev || !dev_replace->tgtdev->bdev) {
     738                 :          0 :                 btrfs_info(fs_info, "cannot continue dev_replace, tgtdev is missing");
     739                 :          0 :                 btrfs_info(fs_info,
     740                 :            :                         "you may cancel the operation after 'mount -o degraded'");
     741                 :          0 :                 btrfs_dev_replace_unlock(dev_replace);
     742                 :          0 :                 return 0;
     743                 :            :         }
     744                 :          0 :         btrfs_dev_replace_unlock(dev_replace);
     745                 :            : 
     746         [ #  # ]:          0 :         WARN_ON(atomic_xchg(
     747                 :            :                 &fs_info->mutually_exclusive_operation_running, 1));
     748         [ #  # ]:          0 :         task = kthread_run(btrfs_dev_replace_kthread, fs_info, "btrfs-devrepl");
     749                 :          0 :         return PTR_ERR_OR_ZERO(task);
     750                 :            : }
     751                 :            : 
     752                 :          0 : static int btrfs_dev_replace_kthread(void *data)
     753                 :            : {
     754                 :            :         struct btrfs_fs_info *fs_info = data;
     755                 :            :         struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
     756                 :            :         struct btrfs_ioctl_dev_replace_args *status_args;
     757                 :            :         u64 progress;
     758                 :            : 
     759                 :            :         status_args = kzalloc(sizeof(*status_args), GFP_NOFS);
     760         [ #  # ]:          0 :         if (status_args) {
     761                 :          0 :                 btrfs_dev_replace_status(fs_info, status_args);
     762                 :          0 :                 progress = status_args->status.progress_1000;
     763                 :          0 :                 kfree(status_args);
     764                 :          0 :                 do_div(progress, 10);
     765 [ #  # ][ #  # ]:          0 :                 printk_in_rcu(KERN_INFO
     766                 :            :                         "BTRFS: continuing dev_replace from %s (devid %llu) to %s @%u%%\n",
     767                 :            :                         dev_replace->srcdev->missing ? "<missing disk>" :
     768                 :            :                         rcu_str_deref(dev_replace->srcdev->name),
     769                 :            :                         dev_replace->srcdev->devid,
     770                 :            :                         dev_replace->tgtdev ?
     771                 :            :                         rcu_str_deref(dev_replace->tgtdev->name) :
     772                 :            :                         "<missing target disk>",
     773                 :            :                         (unsigned int)progress);
     774                 :            :         }
     775                 :          0 :         btrfs_dev_replace_continue_on_mount(fs_info);
     776                 :          0 :         atomic_set(&fs_info->mutually_exclusive_operation_running, 0);
     777                 :            : 
     778                 :          0 :         return 0;
     779                 :            : }
     780                 :            : 
     781                 :          0 : static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info)
     782                 :            : {
     783                 :            :         struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace;
     784                 :            :         int ret;
     785                 :            : 
     786                 :          0 :         ret = btrfs_scrub_dev(fs_info, dev_replace->srcdev->devid,
     787                 :            :                               dev_replace->committed_cursor_left,
     788                 :            :                               dev_replace->srcdev->total_bytes,
     789                 :            :                               &dev_replace->scrub_progress, 0, 1);
     790                 :          0 :         ret = btrfs_dev_replace_finishing(fs_info, ret);
     791         [ #  # ]:          0 :         WARN_ON(ret);
     792                 :          0 :         return 0;
     793                 :            : }
     794                 :            : 
     795                 :          0 : int btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace)
     796                 :            : {
     797         [ #  # ]:          0 :         if (!dev_replace->is_valid)
     798                 :            :                 return 0;
     799                 :            : 
     800 [ #  # ][ #  # ]:          0 :         switch (dev_replace->replace_state) {
     801                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED:
     802                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED:
     803                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED:
     804                 :            :                 return 0;
     805                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED:
     806                 :            :         case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED:
     807                 :            :                 /*
     808                 :            :                  * return true even if tgtdev is missing (this is
     809                 :            :                  * something that can happen if the dev_replace
     810                 :            :                  * procedure is suspended by an umount and then
     811                 :            :                  * the tgtdev is missing (or "btrfs dev scan") was
     812                 :            :                  * not called and the the filesystem is remounted
     813                 :            :                  * in degraded state. This does not stop the
     814                 :            :                  * dev_replace procedure. It needs to be canceled
     815                 :            :                  * manually if the cancelation is wanted.
     816                 :            :                  */
     817                 :            :                 break;
     818                 :            :         }
     819                 :          0 :         return 1;
     820                 :            : }
     821                 :            : 
     822                 :          0 : void btrfs_dev_replace_lock(struct btrfs_dev_replace *dev_replace)
     823                 :            : {
     824                 :            :         /* the beginning is just an optimization for the typical case */
     825         [ #  # ]:          0 :         if (atomic_read(&dev_replace->nesting_level) == 0) {
     826                 :            : acquire_lock:
     827                 :            :                 /* this is not a nested case where the same thread
     828                 :            :                  * is trying to acqurire the same lock twice */
     829                 :          0 :                 mutex_lock(&dev_replace->lock);
     830                 :          0 :                 mutex_lock(&dev_replace->lock_management_lock);
     831                 :          0 :                 dev_replace->lock_owner = current->pid;
     832                 :          0 :                 atomic_inc(&dev_replace->nesting_level);
     833                 :          0 :                 mutex_unlock(&dev_replace->lock_management_lock);
     834                 :          0 :                 return;
     835                 :            :         }
     836                 :            : 
     837                 :          0 :         mutex_lock(&dev_replace->lock_management_lock);
     838 [ #  # ][ #  # ]:          0 :         if (atomic_read(&dev_replace->nesting_level) > 0 &&
     839                 :          0 :             dev_replace->lock_owner == current->pid) {
     840         [ #  # ]:          0 :                 WARN_ON(!mutex_is_locked(&dev_replace->lock));
     841                 :          0 :                 atomic_inc(&dev_replace->nesting_level);
     842                 :          0 :                 mutex_unlock(&dev_replace->lock_management_lock);
     843                 :          0 :                 return;
     844                 :            :         }
     845                 :            : 
     846                 :          0 :         mutex_unlock(&dev_replace->lock_management_lock);
     847                 :          0 :         goto acquire_lock;
     848                 :            : }
     849                 :            : 
     850                 :          0 : void btrfs_dev_replace_unlock(struct btrfs_dev_replace *dev_replace)
     851                 :            : {
     852         [ #  # ]:          0 :         WARN_ON(!mutex_is_locked(&dev_replace->lock));
     853                 :          0 :         mutex_lock(&dev_replace->lock_management_lock);
     854         [ #  # ]:          0 :         WARN_ON(atomic_read(&dev_replace->nesting_level) < 1);
     855         [ #  # ]:          0 :         WARN_ON(dev_replace->lock_owner != current->pid);
     856                 :          0 :         atomic_dec(&dev_replace->nesting_level);
     857         [ #  # ]:          0 :         if (atomic_read(&dev_replace->nesting_level) == 0) {
     858                 :          0 :                 dev_replace->lock_owner = 0;
     859                 :          0 :                 mutex_unlock(&dev_replace->lock_management_lock);
     860                 :          0 :                 mutex_unlock(&dev_replace->lock);
     861                 :            :         } else {
     862                 :          0 :                 mutex_unlock(&dev_replace->lock_management_lock);
     863                 :            :         }
     864                 :          0 : }

Generated by: LCOV version 1.9