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