Skip to content

Commit ccf4ad7

Browse files
committed
zonfs: Fix handling of read-only zones
The write pointer of zones in the read-only consition is defined as invalid by the SCSI ZBC and ATA ZAC specifications. It is thus not possible to determine the correct size of a read-only zone file on mount. Fix this by handling read-only zones in the same manner as offline zones by disabling all accesses to the zone (read and write) and initializing the inode size of the read-only zone to 0). For zones found to be in the read-only condition at runtime, only disable write access to the zone and keep the size of the zone file to its last updated value to allow the user to recover previously written data. Also fix zonefs documentation file to reflect this change. Signed-off-by: Damien Le Moal <[email protected]> Reviewed-by: Johannes Thumshirn <[email protected]>
1 parent 0dda2dd commit ccf4ad7

File tree

2 files changed

+34
-12
lines changed

2 files changed

+34
-12
lines changed

Documentation/filesystems/zonefs.txt

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -258,19 +258,19 @@ conditions.
258258
| option | condition | size read write read write |
259259
+--------------+-----------+-----------------------------------------+
260260
| | good | fixed yes no yes yes |
261-
| remount-ro | read-only | fixed yes no yes no |
261+
| remount-ro | read-only | as is yes no yes no |
262262
| (default) | offline | 0 no no no no |
263263
+--------------+-----------+-----------------------------------------+
264264
| | good | fixed yes no yes yes |
265-
| zone-ro | read-only | fixed yes no yes no |
265+
| zone-ro | read-only | as is yes no yes no |
266266
| | offline | 0 no no no no |
267267
+--------------+-----------+-----------------------------------------+
268268
| | good | 0 no no yes yes |
269269
| zone-offline | read-only | 0 no no yes no |
270270
| | offline | 0 no no no no |
271271
+--------------+-----------+-----------------------------------------+
272272
| | good | fixed yes yes yes yes |
273-
| repair | read-only | fixed yes no yes no |
273+
| repair | read-only | as is yes no yes no |
274274
| | offline | 0 no no no no |
275275
+--------------+-----------+-----------------------------------------+
276276

@@ -307,8 +307,16 @@ condition changes. The defined behaviors are as follow:
307307
* zone-offline
308308
* repair
309309

310-
The I/O error actions defined for each behavior are detailed in the previous
311-
section.
310+
The run-time I/O error actions defined for each behavior are detailed in the
311+
previous section. Mount time I/O errors will cause the mount operation to fail.
312+
The handling of read-only zones also differs between mount-time and run-time.
313+
If a read-only zone is found at mount time, the zone is always treated in the
314+
same manner as offline zones, that is, all accesses are disabled and the zone
315+
file size set to 0. This is necessary as the write pointer of read-only zones
316+
is defined as invalib by the ZBC and ZAC standards, making it impossible to
317+
discover the amount of data that has been written to the zone. In the case of a
318+
read-only zone discovered at run-time, as indicated in the previous section.
319+
the size of the zone file is left unchanged from its last updated value.
312320

313321
Zonefs User Space Tools
314322
=======================

fs/zonefs/super.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,8 @@ static void zonefs_update_stats(struct inode *inode, loff_t new_isize)
178178
* amount of readable data in the zone.
179179
*/
180180
static loff_t zonefs_check_zone_condition(struct inode *inode,
181-
struct blk_zone *zone, bool warn)
181+
struct blk_zone *zone, bool warn,
182+
bool mount)
182183
{
183184
struct zonefs_inode_info *zi = ZONEFS_I(inode);
184185

@@ -196,13 +197,26 @@ static loff_t zonefs_check_zone_condition(struct inode *inode,
196197
zone->wp = zone->start;
197198
return 0;
198199
case BLK_ZONE_COND_READONLY:
199-
/* Do not allow writes in read-only zones */
200+
/*
201+
* The write pointer of read-only zones is invalid. If such a
202+
* zone is found during mount, the file size cannot be retrieved
203+
* so we treat the zone as offline (mount == true case).
204+
* Otherwise, keep the file size as it was when last updated
205+
* so that the user can recover data. In both cases, writes are
206+
* always disabled for the zone.
207+
*/
200208
if (warn)
201209
zonefs_warn(inode->i_sb, "inode %lu: read-only zone\n",
202210
inode->i_ino);
203211
inode->i_flags |= S_IMMUTABLE;
212+
if (mount) {
213+
zone->cond = BLK_ZONE_COND_OFFLINE;
214+
inode->i_mode &= ~0777;
215+
zone->wp = zone->start;
216+
return 0;
217+
}
204218
inode->i_mode &= ~0222;
205-
/* fallthrough */
219+
return i_size_read(inode);
206220
default:
207221
if (zi->i_ztype == ZONEFS_ZTYPE_CNV)
208222
return zi->i_max_size;
@@ -231,7 +245,7 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
231245
* as there is no inconsistency between the inode size and the amount of
232246
* data writen in the zone (data_size).
233247
*/
234-
data_size = zonefs_check_zone_condition(inode, zone, true);
248+
data_size = zonefs_check_zone_condition(inode, zone, true, false);
235249
isize = i_size_read(inode);
236250
if (zone->cond != BLK_ZONE_COND_OFFLINE &&
237251
zone->cond != BLK_ZONE_COND_READONLY &&
@@ -274,7 +288,7 @@ static int zonefs_io_error_cb(struct blk_zone *zone, unsigned int idx,
274288
if (zone->cond != BLK_ZONE_COND_OFFLINE) {
275289
zone->cond = BLK_ZONE_COND_OFFLINE;
276290
data_size = zonefs_check_zone_condition(inode, zone,
277-
false);
291+
false, false);
278292
}
279293
} else if (zone->cond == BLK_ZONE_COND_READONLY ||
280294
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,
283297
if (zone->cond != BLK_ZONE_COND_READONLY) {
284298
zone->cond = BLK_ZONE_COND_READONLY;
285299
data_size = zonefs_check_zone_condition(inode, zone,
286-
false);
300+
false, false);
287301
}
288302
}
289303

@@ -975,7 +989,7 @@ static void zonefs_init_file_inode(struct inode *inode, struct blk_zone *zone,
975989
zi->i_zsector = zone->start;
976990
zi->i_max_size = min_t(loff_t, MAX_LFS_FILESIZE,
977991
zone->len << SECTOR_SHIFT);
978-
zi->i_wpoffset = zonefs_check_zone_condition(inode, zone, true);
992+
zi->i_wpoffset = zonefs_check_zone_condition(inode, zone, true, true);
979993

980994
inode->i_uid = sbi->s_uid;
981995
inode->i_gid = sbi->s_gid;

0 commit comments

Comments
 (0)