Merge tag 'zonefs-5.6-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 25 Mar 2020 17:34:02 +0000 (10:34 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 25 Mar 2020 17:34:02 +0000 (10:34 -0700)
Pull zonefs fix from Damien Le Moal:
 "A single fix from me to correctly handle the size of read-only zone
  files"

* tag 'zonefs-5.6-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/dlemoal/zonefs:
  zonfs: Fix handling of read-only zones

Documentation/filesystems/zonefs.txt
fs/zonefs/super.c

index d54fa98ac1582866ecb7abc4cf19d0790ea3673d..78813c34ec475b3bb8b7ef7a07e6022e9146ccde 100644 (file)
@@ -258,11 +258,11 @@ conditions.
     |    option    | condition | size     read    write    read    write |
     +--------------+-----------+-----------------------------------------+
     |              | good      | fixed    yes     no       yes     yes   |
-    | remount-ro   | read-only | fixed    yes     no       yes     no    |
+    | remount-ro   | read-only | as is    yes     no       yes     no    |
     | (default)    | offline   |   0      no      no       no      no    |
     +--------------+-----------+-----------------------------------------+
     |              | good      | fixed    yes     no       yes     yes   |
-    | zone-ro      | read-only | fixed    yes     no       yes     no    |
+    | zone-ro      | read-only | as is    yes     no       yes     no    |
     |              | offline   |   0      no      no       no      no    |
     +--------------+-----------+-----------------------------------------+
     |              | good      |   0      no      no       yes     yes   |
@@ -270,7 +270,7 @@ conditions.
     |              | offline   |   0      no      no       no      no    |
     +--------------+-----------+-----------------------------------------+
     |              | good      | fixed    yes     yes      yes     yes   |
-    | repair       | read-only | fixed    yes     no       yes     no    |
+    | repair       | read-only | as is    yes     no       yes     no    |
     |              | offline   |   0      no      no       no      no    |
     +--------------+-----------+-----------------------------------------+
 
@@ -307,8 +307,16 @@ condition changes. The defined behaviors are as follow:
 * zone-offline
 * repair
 
-The I/O error actions defined for each behavior are detailed in the previous
-section.
+The run-time I/O error actions defined for each behavior are detailed in the
+previous section. Mount time I/O errors will cause the mount operation to fail.
+The handling of read-only zones also differs between mount-time and run-time.
+If a read-only zone is found at mount time, the zone is always treated in the
+same manner as offline zones, that is, all accesses are disabled and the zone
+file size set to 0. This is necessary as the write pointer of read-only zones
+is defined as invalib by the ZBC and ZAC standards, making it impossible to
+discover the amount of data that has been written to the zone. In the case of a
+read-only zone discovered at run-time, as indicated in the previous section.
+the size of the zone file is left unchanged from its last updated value.
 
 Zonefs User Space Tools
 =======================
index 69aee3dfb6607814cb24d14ea2cdd08642a4c56a..3ce9829a6936da8967062b5bf6ca02f62b748c9a 100644 (file)
@@ -178,7 +178,8 @@ static void zonefs_update_stats(struct inode *inode, loff_t new_isize)
  * amount of readable data in the zone.
  */
 static loff_t zonefs_check_zone_condition(struct inode *inode,
-                                         struct blk_zone *zone, bool warn)
+                                         struct blk_zone *zone, bool warn,
+                                         bool mount)
 {
        struct zonefs_inode_info *zi = ZONEFS_I(inode);
 
@@ -196,13 +197,26 @@ static loff_t zonefs_check_zone_condition(struct inode *inode,
                zone->wp = zone->start;
                return 0;
        case BLK_ZONE_COND_READONLY:
-               /* Do not allow writes in read-only zones */
+               /*
+                * The write pointer of read-only zones is invalid. If such a
+                * zone is found during mount, the file size cannot be retrieved
+                * so we treat the zone as offline (mount == true case).
+                * Otherwise, keep the file size as it was when last updated
+                * so that the user can recover data. In both cases, writes are
+                * always disabled for the zone.
+                */
                if (warn)
                        zonefs_warn(inode->i_sb, "inode %lu: read-only zone\n",
                                    inode->i_ino);
                inode->i_flags |= S_IMMUTABLE;
+               if (mount) {
+                       zone->cond = BLK_ZONE_COND_OFFLINE;
+                       inode->i_mode &= ~0777;
+                       zone->wp = zone->start;
+                       return 0;
+               }
                inode->i_mode &= ~0222;
-               /* fallthrough */
+               return i_size_read(inode);
        default:
                if (zi->i_ztype == ZONEFS_ZTYPE_CNV)
                        return zi->i_max_size;
@@ -231,7 +245,7 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
         * as there is no inconsistency between the inode size and the amount of
         * data writen in the zone (data_size).
         */
-       data_size = zonefs_check_zone_condition(inode, zone, true);
+       data_size = zonefs_check_zone_condition(inode, zone, true, false);
        isize = i_size_read(inode);
        if (zone->cond != BLK_ZONE_COND_OFFLINE &&
            zone->cond != BLK_ZONE_COND_READONLY &&
@@ -274,7 +288,7 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
                if (zone->cond != BLK_ZONE_COND_OFFLINE) {
                        zone->cond = BLK_ZONE_COND_OFFLINE;
                        data_size = zonefs_check_zone_condition(inode, zone,
-                                                               false);
+                                                               false, false);
                }
        } else if (zone->cond == BLK_ZONE_COND_READONLY ||
                   sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZRO) {
@@ -283,7 +297,7 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
                if (zone->cond != BLK_ZONE_COND_READONLY) {
                        zone->cond = BLK_ZONE_COND_READONLY;
                        data_size = zonefs_check_zone_condition(inode, zone,
-                                                               false);
+                                                               false, false);
                }
        }
 
@@ -975,7 +989,7 @@ static void zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
        zi->i_zsector = zone->start;
        zi->i_max_size = min_t(loff_t, MAX_LFS_FILESIZE,
                               zone->len << SECTOR_SHIFT);
-       zi->i_wpoffset = zonefs_check_zone_condition(inode, zone, true);
+       zi->i_wpoffset = zonefs_check_zone_condition(inode, zone, true, true);
 
        inode->i_uid = sbi->s_uid;
        inode->i_gid = sbi->s_gid;