Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

zonefs: Simplify IO error handling

Simplify zonefs_check_zone_condition() by moving the code that changes
an inode access rights to the new function zonefs_inode_update_mode().
Furthermore, since on mount an inode wpoffset is always zero when
zonefs_check_zone_condition() is called during an inode initialization,
the "mount" boolean argument is not necessary for the readonly zone
case. This argument is thus removed.

zonefs_io_error_cb() is also modified to use the inode offline and
zone state flags instead of checking the device zone condition. The
multiple calls to zonefs_check_zone_condition() are reduced to the first
call on entry, which allows removing the "warn" argument.
zonefs_inode_update_mode() is also used to update an inode access rights
as zonefs_io_error_cb() modifies the inode flags depending on the volume
error handling mode (defined with a mount option). Since an inode mode
change differs for read-only zones between mount time and IO error time,
the flag ZONEFS_ZONE_INIT_MODE is used to differentiate both cases.

Signed-off-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>

+64 -55
+59 -51
fs/zonefs/super.c
··· 155 155 * amount of readable data in the zone. 156 156 */ 157 157 static loff_t zonefs_check_zone_condition(struct inode *inode, 158 - struct blk_zone *zone, bool warn, 159 - bool mount) 158 + struct blk_zone *zone) 160 159 { 161 160 struct zonefs_inode_info *zi = ZONEFS_I(inode); 162 161 163 162 switch (zone->cond) { 164 163 case BLK_ZONE_COND_OFFLINE: 165 - /* 166 - * Dead zone: make the inode immutable, disable all accesses 167 - * and set the file size to 0 (zone wp set to zone start). 168 - */ 169 - if (warn) 170 - zonefs_warn(inode->i_sb, "inode %lu: offline zone\n", 171 - inode->i_ino); 172 - inode->i_flags |= S_IMMUTABLE; 173 - inode->i_mode &= ~0777; 174 - zone->wp = zone->start; 164 + zonefs_warn(inode->i_sb, "inode %lu: offline zone\n", 165 + inode->i_ino); 175 166 zi->i_flags |= ZONEFS_ZONE_OFFLINE; 176 167 return 0; 177 168 case BLK_ZONE_COND_READONLY: 178 169 /* 179 - * The write pointer of read-only zones is invalid. If such a 180 - * zone is found during mount, the file size cannot be retrieved 181 - * so we treat the zone as offline (mount == true case). 182 - * Otherwise, keep the file size as it was when last updated 183 - * so that the user can recover data. In both cases, writes are 184 - * always disabled for the zone. 170 + * The write pointer of read-only zones is invalid, so we cannot 171 + * determine the zone wpoffset (inode size). We thus keep the 172 + * zone wpoffset as is, which leads to an empty file 173 + * (wpoffset == 0) on mount. For a runtime error, this keeps 174 + * the inode size as it was when last updated so that the user 175 + * can recover data. 185 176 */ 186 - if (warn) 187 - zonefs_warn(inode->i_sb, "inode %lu: read-only zone\n", 188 - inode->i_ino); 189 - inode->i_flags |= S_IMMUTABLE; 190 - if (mount) { 191 - zone->cond = BLK_ZONE_COND_OFFLINE; 192 - inode->i_mode &= ~0777; 193 - zone->wp = zone->start; 194 - zi->i_flags |= ZONEFS_ZONE_OFFLINE; 195 - return 0; 196 - } 177 + zonefs_warn(inode->i_sb, "inode %lu: read-only zone\n", 178 + inode->i_ino); 197 179 zi->i_flags |= ZONEFS_ZONE_READONLY; 198 - inode->i_mode &= ~0222; 199 - return i_size_read(inode); 180 + if (zi->i_ztype == ZONEFS_ZTYPE_CNV) 181 + return zi->i_max_size; 182 + return zi->i_wpoffset; 200 183 case BLK_ZONE_COND_FULL: 201 184 /* The write pointer of full zones is invalid. */ 202 185 return zi->i_max_size; ··· 188 205 return zi->i_max_size; 189 206 return (zone->wp - zone->start) << SECTOR_SHIFT; 190 207 } 208 + } 209 + 210 + /* 211 + * Check a zone condition and adjust its inode access permissions for 212 + * offline and readonly zones. 213 + */ 214 + static void zonefs_inode_update_mode(struct inode *inode) 215 + { 216 + struct zonefs_inode_info *zi = ZONEFS_I(inode); 217 + 218 + if (zi->i_flags & ZONEFS_ZONE_OFFLINE) { 219 + /* Offline zones cannot be read nor written */ 220 + inode->i_flags |= S_IMMUTABLE; 221 + inode->i_mode &= ~0777; 222 + } else if (zi->i_flags & ZONEFS_ZONE_READONLY) { 223 + /* Readonly zones cannot be written */ 224 + inode->i_flags |= S_IMMUTABLE; 225 + if (zi->i_flags & ZONEFS_ZONE_INIT_MODE) 226 + inode->i_mode &= ~0777; 227 + else 228 + inode->i_mode &= ~0222; 229 + } 230 + 231 + zi->i_flags &= ~ZONEFS_ZONE_INIT_MODE; 191 232 } 192 233 193 234 struct zonefs_ioerr_data { ··· 235 228 * as there is no inconsistency between the inode size and the amount of 236 229 * data writen in the zone (data_size). 237 230 */ 238 - data_size = zonefs_check_zone_condition(inode, zone, true, false); 231 + data_size = zonefs_check_zone_condition(inode, zone); 239 232 isize = i_size_read(inode); 240 - if (zone->cond != BLK_ZONE_COND_OFFLINE && 241 - zone->cond != BLK_ZONE_COND_READONLY && 233 + if (!(zi->i_flags & (ZONEFS_ZONE_READONLY | ZONEFS_ZONE_OFFLINE)) && 242 234 !err->write && isize == data_size) 243 235 return 0; 244 236 ··· 270 264 * zone condition to read-only and offline respectively, as if the 271 265 * condition was signaled by the hardware. 272 266 */ 273 - if (zone->cond == BLK_ZONE_COND_OFFLINE || 274 - sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZOL) { 267 + if ((zi->i_flags & ZONEFS_ZONE_OFFLINE) || 268 + (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZOL)) { 275 269 zonefs_warn(sb, "inode %lu: read/write access disabled\n", 276 270 inode->i_ino); 277 - if (zone->cond != BLK_ZONE_COND_OFFLINE) { 278 - zone->cond = BLK_ZONE_COND_OFFLINE; 279 - data_size = zonefs_check_zone_condition(inode, zone, 280 - false, false); 281 - } 282 - } else if (zone->cond == BLK_ZONE_COND_READONLY || 283 - sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZRO) { 271 + if (!(zi->i_flags & ZONEFS_ZONE_OFFLINE)) 272 + zi->i_flags |= ZONEFS_ZONE_OFFLINE; 273 + zonefs_inode_update_mode(inode); 274 + data_size = 0; 275 + } else if ((zi->i_flags & ZONEFS_ZONE_READONLY) || 276 + (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_ZRO)) { 284 277 zonefs_warn(sb, "inode %lu: write access disabled\n", 285 278 inode->i_ino); 286 - if (zone->cond != BLK_ZONE_COND_READONLY) { 287 - zone->cond = BLK_ZONE_COND_READONLY; 288 - data_size = zonefs_check_zone_condition(inode, zone, 289 - false, false); 290 - } 279 + if (!(zi->i_flags & ZONEFS_ZONE_READONLY)) 280 + zi->i_flags |= ZONEFS_ZONE_READONLY; 281 + zonefs_inode_update_mode(inode); 282 + data_size = isize; 291 283 } else if (sbi->s_mount_opts & ZONEFS_MNTOPT_ERRORS_RO && 292 284 data_size > isize) { 293 285 /* Do not expose garbage data */ ··· 299 295 * close of the zone when the inode file is closed. 300 296 */ 301 297 if ((sbi->s_mount_opts & ZONEFS_MNTOPT_EXPLICIT_OPEN) && 302 - (zone->cond == BLK_ZONE_COND_OFFLINE || 303 - zone->cond == BLK_ZONE_COND_READONLY)) 298 + (zi->i_flags & (ZONEFS_ZONE_READONLY | ZONEFS_ZONE_OFFLINE))) 304 299 zi->i_flags &= ~ZONEFS_ZONE_OPEN; 305 300 306 301 /* ··· 381 378 382 379 inode_init_once(&zi->i_vnode); 383 380 mutex_init(&zi->i_truncate_mutex); 381 + zi->i_wpoffset = 0; 384 382 zi->i_wr_refcnt = 0; 385 383 zi->i_flags = 0; 386 384 ··· 598 594 599 595 zi->i_max_size = min_t(loff_t, MAX_LFS_FILESIZE, 600 596 zone->capacity << SECTOR_SHIFT); 601 - zi->i_wpoffset = zonefs_check_zone_condition(inode, zone, true, true); 597 + zi->i_wpoffset = zonefs_check_zone_condition(inode, zone); 602 598 603 599 inode->i_uid = sbi->s_uid; 604 600 inode->i_gid = sbi->s_gid; ··· 608 604 inode->i_op = &zonefs_file_inode_operations; 609 605 inode->i_fop = &zonefs_file_operations; 610 606 inode->i_mapping->a_ops = &zonefs_file_aops; 607 + 608 + /* Update the inode access rights depending on the zone condition */ 609 + zi->i_flags |= ZONEFS_ZONE_INIT_MODE; 610 + zonefs_inode_update_mode(inode); 611 611 612 612 sb->s_maxbytes = max(zi->i_max_size, sb->s_maxbytes); 613 613 sbi->s_blocks += zi->i_max_size >> sb->s_blocksize_bits;
+5 -4
fs/zonefs/zonefs.h
··· 39 39 return ZONEFS_ZTYPE_SEQ; 40 40 } 41 41 42 - #define ZONEFS_ZONE_OPEN (1U << 0) 43 - #define ZONEFS_ZONE_ACTIVE (1U << 1) 44 - #define ZONEFS_ZONE_OFFLINE (1U << 2) 45 - #define ZONEFS_ZONE_READONLY (1U << 3) 42 + #define ZONEFS_ZONE_INIT_MODE (1U << 0) 43 + #define ZONEFS_ZONE_OPEN (1U << 1) 44 + #define ZONEFS_ZONE_ACTIVE (1U << 2) 45 + #define ZONEFS_ZONE_OFFLINE (1U << 3) 46 + #define ZONEFS_ZONE_READONLY (1U << 4) 46 47 47 48 /* 48 49 * In-memory inode data.