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

Generated by: LCOV version 1.9