Skip to content

Commit 7db1c5d

Browse files
naotakdave
authored andcommitted
btrfs: zoned: support dev-replace in zoned filesystems
This is 4/4 patch to implement device-replace on zoned filesystems. Even after the copying is done, the write pointers of the source device and the destination device may not be synchronized. For example, when the last allocated extent is freed before device-replace process, the extent is not copied, leaving a hole there. Synchronize the write pointers by writing zeroes to the destination device. Reviewed-by: Josef Bacik <[email protected]> Signed-off-by: Naohiro Aota <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent de17add commit 7db1c5d

File tree

3 files changed

+123
-0
lines changed

3 files changed

+123
-0
lines changed

fs/btrfs/scrub.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,9 @@ static int fill_writer_pointer_gap(struct scrub_ctx *sctx, u64 physical)
16281628
if (!btrfs_is_zoned(sctx->fs_info))
16291629
return 0;
16301630

1631+
if (!btrfs_dev_is_sequential(sctx->wr_tgtdev, physical))
1632+
return 0;
1633+
16311634
if (sctx->write_pointer < physical) {
16321635
length = physical - sctx->write_pointer;
16331636

@@ -3069,6 +3072,32 @@ static void sync_replace_for_zoned(struct scrub_ctx *sctx)
30693072
wait_event(sctx->list_wait, atomic_read(&sctx->bios_in_flight) == 0);
30703073
}
30713074

3075+
static int sync_write_pointer_for_zoned(struct scrub_ctx *sctx, u64 logical,
3076+
u64 physical, u64 physical_end)
3077+
{
3078+
struct btrfs_fs_info *fs_info = sctx->fs_info;
3079+
int ret = 0;
3080+
3081+
if (!btrfs_is_zoned(fs_info))
3082+
return 0;
3083+
3084+
wait_event(sctx->list_wait, atomic_read(&sctx->bios_in_flight) == 0);
3085+
3086+
mutex_lock(&sctx->wr_lock);
3087+
if (sctx->write_pointer < physical_end) {
3088+
ret = btrfs_sync_zone_write_pointer(sctx->wr_tgtdev, logical,
3089+
physical,
3090+
sctx->write_pointer);
3091+
if (ret)
3092+
btrfs_err(fs_info,
3093+
"zoned: failed to recover write pointer");
3094+
}
3095+
mutex_unlock(&sctx->wr_lock);
3096+
btrfs_dev_clear_zone_empty(sctx->wr_tgtdev, physical);
3097+
3098+
return ret;
3099+
}
3100+
30723101
static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
30733102
struct map_lookup *map,
30743103
struct btrfs_device *scrub_dev,
@@ -3475,6 +3504,17 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
34753504
blk_finish_plug(&plug);
34763505
btrfs_free_path(path);
34773506
btrfs_free_path(ppath);
3507+
3508+
if (sctx->is_dev_replace && ret >= 0) {
3509+
int ret2;
3510+
3511+
ret2 = sync_write_pointer_for_zoned(sctx, base + offset,
3512+
map->stripes[num].physical,
3513+
physical_end);
3514+
if (ret2)
3515+
ret = ret2;
3516+
}
3517+
34783518
return ret < 0 ? ret : 0;
34793519
}
34803520

fs/btrfs/zoned.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "block-group.h"
1313
#include "transaction.h"
1414
#include "dev-replace.h"
15+
#include "space-info.h"
1516

1617
/* Maximum number of zones to report per blkdev_report_zones() call */
1718
#define BTRFS_REPORT_NR_ZONES 4096
@@ -1385,3 +1386,76 @@ int btrfs_zoned_issue_zeroout(struct btrfs_device *device, u64 physical, u64 len
13851386
return blkdev_issue_zeroout(device->bdev, physical >> SECTOR_SHIFT,
13861387
length >> SECTOR_SHIFT, GFP_NOFS, 0);
13871388
}
1389+
1390+
static int read_zone_info(struct btrfs_fs_info *fs_info, u64 logical,
1391+
struct blk_zone *zone)
1392+
{
1393+
struct btrfs_bio *bbio = NULL;
1394+
u64 mapped_length = PAGE_SIZE;
1395+
unsigned int nofs_flag;
1396+
int nmirrors;
1397+
int i, ret;
1398+
1399+
ret = btrfs_map_sblock(fs_info, BTRFS_MAP_GET_READ_MIRRORS, logical,
1400+
&mapped_length, &bbio);
1401+
if (ret || !bbio || mapped_length < PAGE_SIZE) {
1402+
btrfs_put_bbio(bbio);
1403+
return -EIO;
1404+
}
1405+
1406+
if (bbio->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK)
1407+
return -EINVAL;
1408+
1409+
nofs_flag = memalloc_nofs_save();
1410+
nmirrors = (int)bbio->num_stripes;
1411+
for (i = 0; i < nmirrors; i++) {
1412+
u64 physical = bbio->stripes[i].physical;
1413+
struct btrfs_device *dev = bbio->stripes[i].dev;
1414+
1415+
/* Missing device */
1416+
if (!dev->bdev)
1417+
continue;
1418+
1419+
ret = btrfs_get_dev_zone(dev, physical, zone);
1420+
/* Failing device */
1421+
if (ret == -EIO || ret == -EOPNOTSUPP)
1422+
continue;
1423+
break;
1424+
}
1425+
memalloc_nofs_restore(nofs_flag);
1426+
1427+
return ret;
1428+
}
1429+
1430+
/*
1431+
* Synchronize write pointer in a zone at @physical_start on @tgt_dev, by
1432+
* filling zeros between @physical_pos to a write pointer of dev-replace
1433+
* source device.
1434+
*/
1435+
int btrfs_sync_zone_write_pointer(struct btrfs_device *tgt_dev, u64 logical,
1436+
u64 physical_start, u64 physical_pos)
1437+
{
1438+
struct btrfs_fs_info *fs_info = tgt_dev->fs_info;
1439+
struct blk_zone zone;
1440+
u64 length;
1441+
u64 wp;
1442+
int ret;
1443+
1444+
if (!btrfs_dev_is_sequential(tgt_dev, physical_pos))
1445+
return 0;
1446+
1447+
ret = read_zone_info(fs_info, logical, &zone);
1448+
if (ret)
1449+
return ret;
1450+
1451+
wp = physical_start + ((zone.wp - zone.start) << SECTOR_SHIFT);
1452+
1453+
if (physical_pos == wp)
1454+
return 0;
1455+
1456+
if (physical_pos > wp)
1457+
return -EUCLEAN;
1458+
1459+
length = wp - physical_pos;
1460+
return btrfs_zoned_issue_zeroout(tgt_dev, physical_pos, length);
1461+
}

fs/btrfs/zoned.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ bool btrfs_check_meta_write_pointer(struct btrfs_fs_info *fs_info,
5656
void btrfs_revert_meta_write_pointer(struct btrfs_block_group *cache,
5757
struct extent_buffer *eb);
5858
int btrfs_zoned_issue_zeroout(struct btrfs_device *device, u64 physical, u64 length);
59+
int btrfs_sync_zone_write_pointer(struct btrfs_device *tgt_dev, u64 logical,
60+
u64 physical_start, u64 physical_pos);
5961
#else /* CONFIG_BLK_DEV_ZONED */
6062
static inline int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos,
6163
struct blk_zone *zone)
@@ -176,6 +178,13 @@ static inline int btrfs_zoned_issue_zeroout(struct btrfs_device *device,
176178
return -EOPNOTSUPP;
177179
}
178180

181+
static inline int btrfs_sync_zone_write_pointer(struct btrfs_device *tgt_dev,
182+
u64 logical, u64 physical_start,
183+
u64 physical_pos)
184+
{
185+
return -EOPNOTSUPP;
186+
}
187+
179188
#endif
180189

181190
static inline bool btrfs_dev_is_sequential(struct btrfs_device *device, u64 pos)

0 commit comments

Comments
 (0)