@@ -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 */
180180static 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