OSDN Git Service

btrfs: zoned: finish superblock zone once no space left for new SB
authorNaohiro Aota <naohiro.aota@wdc.com>
Thu, 19 Aug 2021 12:19:14 +0000 (21:19 +0900)
committerDavid Sterba <dsterba@suse.com>
Tue, 26 Oct 2021 17:07:59 +0000 (19:07 +0200)
If there is no more space left for a new superblock in a superblock zone,
then it is better to ZONE_FINISH the zone and frees up the active zone
count.

Since btrfs_advance_sb_log() can now issue REQ_OP_ZONE_FINISH, we also need
to convert it to return int for the error case.

Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/disk-io.c
fs/btrfs/zoned.c
fs/btrfs/zoned.h

index 71aafe9..f755d02 100644 (file)
@@ -3887,7 +3887,9 @@ static int write_dev_supers(struct btrfs_device *device,
                        bio->bi_opf |= REQ_FUA;
 
                btrfsic_submit_bio(bio);
-               btrfs_advance_sb_log(device, i);
+
+               if (btrfs_advance_sb_log(device, i))
+                       errors++;
        }
        return errors < i ? 0 : -1;
 }
index 9cfb5b7..17554ca 100644 (file)
@@ -789,36 +789,56 @@ static inline bool is_sb_log_zone(struct btrfs_zoned_device_info *zinfo,
        return true;
 }
 
-void btrfs_advance_sb_log(struct btrfs_device *device, int mirror)
+int btrfs_advance_sb_log(struct btrfs_device *device, int mirror)
 {
        struct btrfs_zoned_device_info *zinfo = device->zone_info;
        struct blk_zone *zone;
+       int i;
 
        if (!is_sb_log_zone(zinfo, mirror))
-               return;
+               return 0;
 
        zone = &zinfo->sb_zones[BTRFS_NR_SB_LOG_ZONES * mirror];
-       if (zone->cond != BLK_ZONE_COND_FULL) {
+       for (i = 0; i < BTRFS_NR_SB_LOG_ZONES; i++) {
+               /* Advance the next zone */
+               if (zone->cond == BLK_ZONE_COND_FULL) {
+                       zone++;
+                       continue;
+               }
+
                if (zone->cond == BLK_ZONE_COND_EMPTY)
                        zone->cond = BLK_ZONE_COND_IMP_OPEN;
 
-               zone->wp += (BTRFS_SUPER_INFO_SIZE >> SECTOR_SHIFT);
+               zone->wp += SUPER_INFO_SECTORS;
+
+               if (sb_zone_is_full(zone)) {
+                       /*
+                        * No room left to write new superblock. Since
+                        * superblock is written with REQ_SYNC, it is safe to
+                        * finish the zone now.
+                        *
+                        * If the write pointer is exactly at the capacity,
+                        * explicit ZONE_FINISH is not necessary.
+                        */
+                       if (zone->wp != zone->start + zone->capacity) {
+                               int ret;
+
+                               ret = blkdev_zone_mgmt(device->bdev,
+                                               REQ_OP_ZONE_FINISH, zone->start,
+                                               zone->len, GFP_NOFS);
+                               if (ret)
+                                       return ret;
+                       }
 
-               if (zone->wp == zone->start + zone->len)
+                       zone->wp = zone->start + zone->len;
                        zone->cond = BLK_ZONE_COND_FULL;
-
-               return;
+               }
+               return 0;
        }
 
-       zone++;
-       ASSERT(zone->cond != BLK_ZONE_COND_FULL);
-       if (zone->cond == BLK_ZONE_COND_EMPTY)
-               zone->cond = BLK_ZONE_COND_IMP_OPEN;
-
-       zone->wp += (BTRFS_SUPER_INFO_SIZE >> SECTOR_SHIFT);
-
-       if (zone->wp == zone->start + zone->len)
-               zone->cond = BLK_ZONE_COND_FULL;
+       /* All the zones are FULL. Should not reach here. */
+       ASSERT(0);
+       return -EIO;
 }
 
 int btrfs_reset_sb_log_zones(struct block_device *bdev, int mirror)
index 4b29970..4f30f3b 100644 (file)
@@ -40,7 +40,7 @@ int btrfs_sb_log_location_bdev(struct block_device *bdev, int mirror, int rw,
                               u64 *bytenr_ret);
 int btrfs_sb_log_location(struct btrfs_device *device, int mirror, int rw,
                          u64 *bytenr_ret);
-void btrfs_advance_sb_log(struct btrfs_device *device, int mirror);
+int btrfs_advance_sb_log(struct btrfs_device *device, int mirror);
 int btrfs_reset_sb_log_zones(struct block_device *bdev, int mirror);
 u64 btrfs_find_allocatable_zones(struct btrfs_device *device, u64 hole_start,
                                 u64 hole_end, u64 num_bytes);
@@ -113,8 +113,10 @@ static inline int btrfs_sb_log_location(struct btrfs_device *device, int mirror,
        return 0;
 }
 
-static inline void btrfs_advance_sb_log(struct btrfs_device *device, int mirror)
-{ }
+static inline int btrfs_advance_sb_log(struct btrfs_device *device, int mirror)
+{
+       return 0;
+}
 
 static inline int btrfs_reset_sb_log_zones(struct block_device *bdev, int mirror)
 {