Skip to content

Commit 52a4a14

Browse files
author
Chandan Babu R
committed
xfs: Introduce per-inode 64-bit extent counters
This commit introduces new fields in the on-disk inode format to support 64-bit data fork extent counters and 32-bit attribute fork extent counters. The new fields will be used only when an inode has XFS_DIFLAG2_NREXT64 flag set. Otherwise we continue to use the regular 32-bit data fork extent counters and 16-bit attribute fork extent counters. Reviewed-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Chandan Babu R <chandan.babu@oracle.com> Suggested-by: Dave Chinner <dchinner@redhat.com>
1 parent 8314bca commit 52a4a14

6 files changed

Lines changed: 204 additions & 30 deletions

File tree

fs/xfs/libxfs/xfs_format.h

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -792,16 +792,41 @@ struct xfs_dinode {
792792
__be32 di_nlink; /* number of links to file */
793793
__be16 di_projid_lo; /* lower part of owner's project id */
794794
__be16 di_projid_hi; /* higher part owner's project id */
795-
__u8 di_pad[6]; /* unused, zeroed space */
796-
__be16 di_flushiter; /* incremented on flush */
795+
union {
796+
/* Number of data fork extents if NREXT64 is set */
797+
__be64 di_big_nextents;
798+
799+
/* Padding for V3 inodes without NREXT64 set. */
800+
__be64 di_v3_pad;
801+
802+
/* Padding and inode flush counter for V2 inodes. */
803+
struct {
804+
__u8 di_v2_pad[6];
805+
__be16 di_flushiter;
806+
};
807+
};
797808
xfs_timestamp_t di_atime; /* time last accessed */
798809
xfs_timestamp_t di_mtime; /* time last modified */
799810
xfs_timestamp_t di_ctime; /* time created/inode modified */
800811
__be64 di_size; /* number of bytes in file */
801812
__be64 di_nblocks; /* # of direct & btree blocks used */
802813
__be32 di_extsize; /* basic/minimum extent size for file */
803-
__be32 di_nextents; /* number of extents in data fork */
804-
__be16 di_anextents; /* number of extents in attribute fork*/
814+
union {
815+
/*
816+
* For V2 inodes and V3 inodes without NREXT64 set, this
817+
* is the number of data and attr fork extents.
818+
*/
819+
struct {
820+
__be32 di_nextents;
821+
__be16 di_anextents;
822+
} __packed;
823+
824+
/* Number of attr fork extents if NREXT64 is set. */
825+
struct {
826+
__be32 di_big_anextents;
827+
__be16 di_nrext64_pad;
828+
} __packed;
829+
} __packed;
805830
__u8 di_forkoff; /* attr fork offs, <<3 for 64b align */
806831
__s8 di_aformat; /* format of attr fork's data */
807832
__be32 di_dmevmask; /* DMIG event mask */

fs/xfs/libxfs/xfs_inode_buf.c

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,25 @@ xfs_inode_to_disk_ts(
279279
return ts;
280280
}
281281

282+
static inline void
283+
xfs_inode_to_disk_iext_counters(
284+
struct xfs_inode *ip,
285+
struct xfs_dinode *to)
286+
{
287+
if (xfs_inode_has_large_extent_counts(ip)) {
288+
to->di_big_nextents = cpu_to_be64(xfs_ifork_nextents(&ip->i_df));
289+
to->di_big_anextents = cpu_to_be32(xfs_ifork_nextents(ip->i_afp));
290+
/*
291+
* We might be upgrading the inode to use larger extent counters
292+
* than was previously used. Hence zero the unused field.
293+
*/
294+
to->di_nrext64_pad = cpu_to_be16(0);
295+
} else {
296+
to->di_nextents = cpu_to_be32(xfs_ifork_nextents(&ip->i_df));
297+
to->di_anextents = cpu_to_be16(xfs_ifork_nextents(ip->i_afp));
298+
}
299+
}
300+
282301
void
283302
xfs_inode_to_disk(
284303
struct xfs_inode *ip,
@@ -296,7 +315,6 @@ xfs_inode_to_disk(
296315
to->di_projid_lo = cpu_to_be16(ip->i_projid & 0xffff);
297316
to->di_projid_hi = cpu_to_be16(ip->i_projid >> 16);
298317

299-
memset(to->di_pad, 0, sizeof(to->di_pad));
300318
to->di_atime = xfs_inode_to_disk_ts(ip, inode->i_atime);
301319
to->di_mtime = xfs_inode_to_disk_ts(ip, inode->i_mtime);
302320
to->di_ctime = xfs_inode_to_disk_ts(ip, inode->i_ctime);
@@ -307,8 +325,6 @@ xfs_inode_to_disk(
307325
to->di_size = cpu_to_be64(ip->i_disk_size);
308326
to->di_nblocks = cpu_to_be64(ip->i_nblocks);
309327
to->di_extsize = cpu_to_be32(ip->i_extsize);
310-
to->di_nextents = cpu_to_be32(xfs_ifork_nextents(&ip->i_df));
311-
to->di_anextents = cpu_to_be16(xfs_ifork_nextents(ip->i_afp));
312328
to->di_forkoff = ip->i_forkoff;
313329
to->di_aformat = xfs_ifork_format(ip->i_afp);
314330
to->di_flags = cpu_to_be16(ip->i_diflags);
@@ -323,11 +339,14 @@ xfs_inode_to_disk(
323339
to->di_lsn = cpu_to_be64(lsn);
324340
memset(to->di_pad2, 0, sizeof(to->di_pad2));
325341
uuid_copy(&to->di_uuid, &ip->i_mount->m_sb.sb_meta_uuid);
326-
to->di_flushiter = 0;
342+
to->di_v3_pad = 0;
327343
} else {
328344
to->di_version = 2;
329345
to->di_flushiter = cpu_to_be16(ip->i_flushiter);
346+
memset(to->di_v2_pad, 0, sizeof(to->di_v2_pad));
330347
}
348+
349+
xfs_inode_to_disk_iext_counters(ip, to);
331350
}
332351

333352
static xfs_failaddr_t
@@ -398,6 +417,24 @@ xfs_dinode_verify_forkoff(
398417
return NULL;
399418
}
400419

420+
static xfs_failaddr_t
421+
xfs_dinode_verify_nrext64(
422+
struct xfs_mount *mp,
423+
struct xfs_dinode *dip)
424+
{
425+
if (xfs_dinode_has_large_extent_counts(dip)) {
426+
if (!xfs_has_large_extent_counts(mp))
427+
return __this_address;
428+
if (dip->di_nrext64_pad != 0)
429+
return __this_address;
430+
} else if (dip->di_version >= 3) {
431+
if (dip->di_v3_pad != 0)
432+
return __this_address;
433+
}
434+
435+
return NULL;
436+
}
437+
401438
xfs_failaddr_t
402439
xfs_dinode_verify(
403440
struct xfs_mount *mp,
@@ -442,6 +479,10 @@ xfs_dinode_verify(
442479
if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0)
443480
return __this_address;
444481

482+
fa = xfs_dinode_verify_nrext64(mp, dip);
483+
if (fa)
484+
return fa;
485+
445486
nextents = xfs_dfork_data_extents(dip);
446487
naextents = xfs_dfork_attr_extents(dip);
447488
nblocks = be64_to_cpu(dip->di_nblocks);

fs/xfs/libxfs/xfs_inode_fork.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,19 @@ static inline xfs_extnum_t
158158
xfs_dfork_data_extents(
159159
struct xfs_dinode *dip)
160160
{
161+
if (xfs_dinode_has_large_extent_counts(dip))
162+
return be64_to_cpu(dip->di_big_nextents);
163+
161164
return be32_to_cpu(dip->di_nextents);
162165
}
163166

164167
static inline xfs_extnum_t
165168
xfs_dfork_attr_extents(
166169
struct xfs_dinode *dip)
167170
{
171+
if (xfs_dinode_has_large_extent_counts(dip))
172+
return be32_to_cpu(dip->di_big_anextents);
173+
168174
return be16_to_cpu(dip->di_anextents);
169175
}
170176

fs/xfs/libxfs/xfs_log_format.h

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -388,16 +388,41 @@ struct xfs_log_dinode {
388388
uint32_t di_nlink; /* number of links to file */
389389
uint16_t di_projid_lo; /* lower part of owner's project id */
390390
uint16_t di_projid_hi; /* higher part of owner's project id */
391-
uint8_t di_pad[6]; /* unused, zeroed space */
392-
uint16_t di_flushiter; /* incremented on flush */
391+
union {
392+
/* Number of data fork extents if NREXT64 is set */
393+
uint64_t di_big_nextents;
394+
395+
/* Padding for V3 inodes without NREXT64 set. */
396+
uint64_t di_v3_pad;
397+
398+
/* Padding and inode flush counter for V2 inodes. */
399+
struct {
400+
uint8_t di_v2_pad[6]; /* V2 inode zeroed space */
401+
uint16_t di_flushiter; /* V2 inode incremented on flush */
402+
};
403+
};
393404
xfs_log_timestamp_t di_atime; /* time last accessed */
394405
xfs_log_timestamp_t di_mtime; /* time last modified */
395406
xfs_log_timestamp_t di_ctime; /* time created/inode modified */
396407
xfs_fsize_t di_size; /* number of bytes in file */
397408
xfs_rfsblock_t di_nblocks; /* # of direct & btree blocks used */
398409
xfs_extlen_t di_extsize; /* basic/minimum extent size for file */
399-
uint32_t di_nextents; /* number of extents in data fork */
400-
uint16_t di_anextents; /* number of extents in attribute fork*/
410+
union {
411+
/*
412+
* For V2 inodes and V3 inodes without NREXT64 set, this
413+
* is the number of data and attr fork extents.
414+
*/
415+
struct {
416+
uint32_t di_nextents;
417+
uint16_t di_anextents;
418+
} __packed;
419+
420+
/* Number of attr fork extents if NREXT64 is set. */
421+
struct {
422+
uint32_t di_big_anextents;
423+
uint16_t di_nrext64_pad;
424+
} __packed;
425+
} __packed;
401426
uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */
402427
int8_t di_aformat; /* format of attr fork's data */
403428
uint32_t di_dmevmask; /* DMIG event mask */

fs/xfs/xfs_inode_item.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,21 @@ xfs_copy_dm_fields_to_log_dinode(
359359
}
360360
}
361361

362+
static inline void
363+
xfs_inode_to_log_dinode_iext_counters(
364+
struct xfs_inode *ip,
365+
struct xfs_log_dinode *to)
366+
{
367+
if (xfs_inode_has_large_extent_counts(ip)) {
368+
to->di_big_nextents = xfs_ifork_nextents(&ip->i_df);
369+
to->di_big_anextents = xfs_ifork_nextents(ip->i_afp);
370+
to->di_nrext64_pad = 0;
371+
} else {
372+
to->di_nextents = xfs_ifork_nextents(&ip->i_df);
373+
to->di_anextents = xfs_ifork_nextents(ip->i_afp);
374+
}
375+
}
376+
362377
static void
363378
xfs_inode_to_log_dinode(
364379
struct xfs_inode *ip,
@@ -374,7 +389,6 @@ xfs_inode_to_log_dinode(
374389
to->di_projid_lo = ip->i_projid & 0xffff;
375390
to->di_projid_hi = ip->i_projid >> 16;
376391

377-
memset(to->di_pad, 0, sizeof(to->di_pad));
378392
memset(to->di_pad3, 0, sizeof(to->di_pad3));
379393
to->di_atime = xfs_inode_to_log_dinode_ts(ip, inode->i_atime);
380394
to->di_mtime = xfs_inode_to_log_dinode_ts(ip, inode->i_mtime);
@@ -386,8 +400,6 @@ xfs_inode_to_log_dinode(
386400
to->di_size = ip->i_disk_size;
387401
to->di_nblocks = ip->i_nblocks;
388402
to->di_extsize = ip->i_extsize;
389-
to->di_nextents = xfs_ifork_nextents(&ip->i_df);
390-
to->di_anextents = xfs_ifork_nextents(ip->i_afp);
391403
to->di_forkoff = ip->i_forkoff;
392404
to->di_aformat = xfs_ifork_format(ip->i_afp);
393405
to->di_flags = ip->i_diflags;
@@ -407,11 +419,14 @@ xfs_inode_to_log_dinode(
407419
to->di_lsn = lsn;
408420
memset(to->di_pad2, 0, sizeof(to->di_pad2));
409421
uuid_copy(&to->di_uuid, &ip->i_mount->m_sb.sb_meta_uuid);
410-
to->di_flushiter = 0;
422+
to->di_v3_pad = 0;
411423
} else {
412424
to->di_version = 2;
413425
to->di_flushiter = ip->i_flushiter;
426+
memset(to->di_v2_pad, 0, sizeof(to->di_v2_pad));
414427
}
428+
429+
xfs_inode_to_log_dinode_iext_counters(ip, to);
415430
}
416431

417432
/*

fs/xfs/xfs_inode_item_recover.c

Lines changed: 76 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,22 @@ static inline bool xfs_log_dinode_has_large_extent_counts(
149149
(ld->di_flags2 & XFS_DIFLAG2_NREXT64);
150150
}
151151

152+
static inline void
153+
xfs_log_dinode_to_disk_iext_counters(
154+
struct xfs_log_dinode *from,
155+
struct xfs_dinode *to)
156+
{
157+
if (xfs_log_dinode_has_large_extent_counts(from)) {
158+
to->di_big_nextents = cpu_to_be64(from->di_big_nextents);
159+
to->di_big_anextents = cpu_to_be32(from->di_big_anextents);
160+
to->di_nrext64_pad = cpu_to_be16(from->di_nrext64_pad);
161+
} else {
162+
to->di_nextents = cpu_to_be32(from->di_nextents);
163+
to->di_anextents = cpu_to_be16(from->di_anextents);
164+
}
165+
166+
}
167+
152168
STATIC void
153169
xfs_log_dinode_to_disk(
154170
struct xfs_log_dinode *from,
@@ -165,7 +181,6 @@ xfs_log_dinode_to_disk(
165181
to->di_nlink = cpu_to_be32(from->di_nlink);
166182
to->di_projid_lo = cpu_to_be16(from->di_projid_lo);
167183
to->di_projid_hi = cpu_to_be16(from->di_projid_hi);
168-
memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad));
169184

170185
to->di_atime = xfs_log_dinode_to_disk_ts(from, from->di_atime);
171186
to->di_mtime = xfs_log_dinode_to_disk_ts(from, from->di_mtime);
@@ -174,8 +189,6 @@ xfs_log_dinode_to_disk(
174189
to->di_size = cpu_to_be64(from->di_size);
175190
to->di_nblocks = cpu_to_be64(from->di_nblocks);
176191
to->di_extsize = cpu_to_be32(from->di_extsize);
177-
to->di_nextents = cpu_to_be32(from->di_nextents);
178-
to->di_anextents = cpu_to_be16(from->di_anextents);
179192
to->di_forkoff = from->di_forkoff;
180193
to->di_aformat = from->di_aformat;
181194
to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
@@ -191,12 +204,66 @@ xfs_log_dinode_to_disk(
191204
to->di_cowextsize = cpu_to_be32(from->di_cowextsize);
192205
to->di_ino = cpu_to_be64(from->di_ino);
193206
to->di_lsn = cpu_to_be64(lsn);
194-
memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2));
207+
memset(to->di_pad2, 0, sizeof(to->di_pad2));
195208
uuid_copy(&to->di_uuid, &from->di_uuid);
196-
to->di_flushiter = 0;
209+
to->di_v3_pad = 0;
197210
} else {
198211
to->di_flushiter = cpu_to_be16(from->di_flushiter);
212+
memset(to->di_v2_pad, 0, sizeof(to->di_v2_pad));
213+
}
214+
215+
xfs_log_dinode_to_disk_iext_counters(from, to);
216+
}
217+
218+
STATIC int
219+
xlog_dinode_verify_extent_counts(
220+
struct xfs_mount *mp,
221+
struct xfs_log_dinode *ldip)
222+
{
223+
xfs_extnum_t nextents;
224+
xfs_aextnum_t anextents;
225+
226+
if (xfs_log_dinode_has_large_extent_counts(ldip)) {
227+
if (!xfs_has_large_extent_counts(mp) ||
228+
(ldip->di_nrext64_pad != 0)) {
229+
XFS_CORRUPTION_ERROR(
230+
"Bad log dinode large extent count format",
231+
XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));
232+
xfs_alert(mp,
233+
"Bad inode 0x%llx, large extent counts %d, padding 0x%x",
234+
ldip->di_ino, xfs_has_large_extent_counts(mp),
235+
ldip->di_nrext64_pad);
236+
return -EFSCORRUPTED;
237+
}
238+
239+
nextents = ldip->di_big_nextents;
240+
anextents = ldip->di_big_anextents;
241+
} else {
242+
if (ldip->di_version == 3 && ldip->di_v3_pad != 0) {
243+
XFS_CORRUPTION_ERROR(
244+
"Bad log dinode di_v3_pad",
245+
XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));
246+
xfs_alert(mp,
247+
"Bad inode 0x%llx, di_v3_pad 0x%llx",
248+
ldip->di_ino, ldip->di_v3_pad);
249+
return -EFSCORRUPTED;
250+
}
251+
252+
nextents = ldip->di_nextents;
253+
anextents = ldip->di_anextents;
254+
}
255+
256+
if (unlikely(nextents + anextents > ldip->di_nblocks)) {
257+
XFS_CORRUPTION_ERROR("Bad log dinode extent counts",
258+
XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));
259+
xfs_alert(mp,
260+
"Bad inode 0x%llx, large extent counts %d, nextents 0x%llx, anextents 0x%x, nblocks 0x%llx",
261+
ldip->di_ino, xfs_has_large_extent_counts(mp), nextents,
262+
anextents, ldip->di_nblocks);
263+
return -EFSCORRUPTED;
199264
}
265+
266+
return 0;
200267
}
201268

202269
STATIC int
@@ -347,16 +414,11 @@ xlog_recover_inode_commit_pass2(
347414
goto out_release;
348415
}
349416
}
350-
if (unlikely(ldip->di_nextents + ldip->di_anextents > ldip->di_nblocks)){
351-
XFS_CORRUPTION_ERROR("Bad log dinode extent counts",
352-
XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));
353-
xfs_alert(mp,
354-
"Bad inode 0x%llx, nextents 0x%x, anextents 0x%x, nblocks 0x%llx",
355-
in_f->ilf_ino, ldip->di_nextents, ldip->di_anextents,
356-
ldip->di_nblocks);
357-
error = -EFSCORRUPTED;
417+
418+
error = xlog_dinode_verify_extent_counts(mp, ldip);
419+
if (error)
358420
goto out_release;
359-
}
421+
360422
if (unlikely(ldip->di_forkoff > mp->m_sb.sb_inodesize)) {
361423
XFS_CORRUPTION_ERROR("Bad log dinode fork offset",
362424
XFS_ERRLEVEL_LOW, mp, ldip, sizeof(*ldip));

0 commit comments

Comments
 (0)