Commit 6d313498f035abc9d8ad3a1b3295f133bfab9638

Authored by Dave Chinner
Committed by Ben Myers
1 parent 89c6c89af2

xfs: dirent dtype presence is dependent on directory magic numbers

The determination of whether a directory entry contains a dtype
field originally was dependent on the filesystem having CRCs
enabled. This meant that the format for dtype beign enabled could be
determined by checking the directory block magic number rather than
doing a feature bit check. This was useful in that it meant that we
didn't need to pass a struct xfs_mount around to functions that
were already supplied with a directory block header.

Unfortunately, the introduction of dtype fields into the v4
structure via a feature bit meant this "use the directory block
magic number" method of discriminating the dirent entry sizes is
broken. Hence we need to convert the places that use magic number
checks to use feature bit checks so that they work correctly and not
by chance.

The current code works on v4 filesystems only because the dirent
size roundup covers the extra byte needed by the dtype field in the
places where this problem occurs.

Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Ben Myers <bpm@sgi.com>
Signed-off-by: Ben Myers <bpm@sgi.com>

(cherry picked from commit 367993e7c6428cb7617ab7653d61dca54e2fdede)

Showing 4 changed files with 28 additions and 39 deletions Side-by-side Diff

fs/xfs/xfs_dir2_block.c
... ... @@ -1158,7 +1158,7 @@
1158 1158 /*
1159 1159 * Create entry for .
1160 1160 */
1161   - dep = xfs_dir3_data_dot_entry_p(hdr);
  1161 + dep = xfs_dir3_data_dot_entry_p(mp, hdr);
1162 1162 dep->inumber = cpu_to_be64(dp->i_ino);
1163 1163 dep->namelen = 1;
1164 1164 dep->name[0] = '.';
... ... @@ -1172,7 +1172,7 @@
1172 1172 /*
1173 1173 * Create entry for ..
1174 1174 */
1175   - dep = xfs_dir3_data_dotdot_entry_p(hdr);
  1175 + dep = xfs_dir3_data_dotdot_entry_p(mp, hdr);
1176 1176 dep->inumber = cpu_to_be64(xfs_dir2_sf_get_parent_ino(sfp));
1177 1177 dep->namelen = 2;
1178 1178 dep->name[0] = dep->name[1] = '.';
... ... @@ -1183,7 +1183,7 @@
1183 1183 blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot);
1184 1184 blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,
1185 1185 (char *)dep - (char *)hdr));
1186   - offset = xfs_dir3_data_first_offset(hdr);
  1186 + offset = xfs_dir3_data_first_offset(mp);
1187 1187 /*
1188 1188 * Loop over existing entries, stuff them in.
1189 1189 */
fs/xfs/xfs_dir2_format.h
... ... @@ -497,69 +497,58 @@
497 497 /*
498 498 * Offsets of . and .. in data space (always block 0)
499 499 *
500   - * The macros are used for shortform directories as they have no headers to read
501   - * the magic number out of. Shortform directories need to know the size of the
502   - * data block header because the sfe embeds the block offset of the entry into
503   - * it so that it doesn't change when format conversion occurs. Bad Things Happen
504   - * if we don't follow this rule.
505   - *
506 500 * XXX: there is scope for significant optimisation of the logic here. Right
507 501 * now we are checking for "dir3 format" over and over again. Ideally we should
508 502 * only do it once for each operation.
509 503 */
510   -#define XFS_DIR3_DATA_DOT_OFFSET(mp) \
511   - xfs_dir3_data_hdr_size(xfs_sb_version_hascrc(&(mp)->m_sb))
512   -#define XFS_DIR3_DATA_DOTDOT_OFFSET(mp) \
513   - (XFS_DIR3_DATA_DOT_OFFSET(mp) + xfs_dir3_data_entsize(mp, 1))
514   -#define XFS_DIR3_DATA_FIRST_OFFSET(mp) \
515   - (XFS_DIR3_DATA_DOTDOT_OFFSET(mp) + xfs_dir3_data_entsize(mp, 2))
516   -
517 504 static inline xfs_dir2_data_aoff_t
518   -xfs_dir3_data_dot_offset(struct xfs_dir2_data_hdr *hdr)
  505 +xfs_dir3_data_dot_offset(struct xfs_mount *mp)
519 506 {
520   - return xfs_dir3_data_entry_offset(hdr);
  507 + return xfs_dir3_data_hdr_size(xfs_sb_version_hascrc(&mp->m_sb));
521 508 }
522 509  
523 510 static inline xfs_dir2_data_aoff_t
524   -xfs_dir3_data_dotdot_offset(struct xfs_dir2_data_hdr *hdr)
  511 +xfs_dir3_data_dotdot_offset(struct xfs_mount *mp)
525 512 {
526   - bool dir3 = hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
527   - hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
528   - return xfs_dir3_data_dot_offset(hdr) +
529   - __xfs_dir3_data_entsize(dir3, 1);
  513 + return xfs_dir3_data_dot_offset(mp) +
  514 + xfs_dir3_data_entsize(mp, 1);
530 515 }
531 516  
532 517 static inline xfs_dir2_data_aoff_t
533   -xfs_dir3_data_first_offset(struct xfs_dir2_data_hdr *hdr)
  518 +xfs_dir3_data_first_offset(struct xfs_mount *mp)
534 519 {
535   - bool dir3 = hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) ||
536   - hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC);
537   - return xfs_dir3_data_dotdot_offset(hdr) +
538   - __xfs_dir3_data_entsize(dir3, 2);
  520 + return xfs_dir3_data_dotdot_offset(mp) +
  521 + xfs_dir3_data_entsize(mp, 2);
539 522 }
540 523  
541 524 /*
542 525 * location of . and .. in data space (always block 0)
543 526 */
544 527 static inline struct xfs_dir2_data_entry *
545   -xfs_dir3_data_dot_entry_p(struct xfs_dir2_data_hdr *hdr)
  528 +xfs_dir3_data_dot_entry_p(
  529 + struct xfs_mount *mp,
  530 + struct xfs_dir2_data_hdr *hdr)
546 531 {
547 532 return (struct xfs_dir2_data_entry *)
548   - ((char *)hdr + xfs_dir3_data_dot_offset(hdr));
  533 + ((char *)hdr + xfs_dir3_data_dot_offset(mp));
549 534 }
550 535  
551 536 static inline struct xfs_dir2_data_entry *
552   -xfs_dir3_data_dotdot_entry_p(struct xfs_dir2_data_hdr *hdr)
  537 +xfs_dir3_data_dotdot_entry_p(
  538 + struct xfs_mount *mp,
  539 + struct xfs_dir2_data_hdr *hdr)
553 540 {
554 541 return (struct xfs_dir2_data_entry *)
555   - ((char *)hdr + xfs_dir3_data_dotdot_offset(hdr));
  542 + ((char *)hdr + xfs_dir3_data_dotdot_offset(mp));
556 543 }
557 544  
558 545 static inline struct xfs_dir2_data_entry *
559   -xfs_dir3_data_first_entry_p(struct xfs_dir2_data_hdr *hdr)
  546 +xfs_dir3_data_first_entry_p(
  547 + struct xfs_mount *mp,
  548 + struct xfs_dir2_data_hdr *hdr)
560 549 {
561 550 return (struct xfs_dir2_data_entry *)
562   - ((char *)hdr + xfs_dir3_data_first_offset(hdr));
  551 + ((char *)hdr + xfs_dir3_data_first_offset(mp));
563 552 }
564 553  
565 554 /*
fs/xfs/xfs_dir2_readdir.c
... ... @@ -119,9 +119,9 @@
119 119 * mp->m_dirdatablk.
120 120 */
121 121 dot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
122   - XFS_DIR3_DATA_DOT_OFFSET(mp));
  122 + xfs_dir3_data_dot_offset(mp));
123 123 dotdot_offset = xfs_dir2_db_off_to_dataptr(mp, mp->m_dirdatablk,
124   - XFS_DIR3_DATA_DOTDOT_OFFSET(mp));
  124 + xfs_dir3_data_dotdot_offset(mp));
125 125  
126 126 /*
127 127 * Put . entry unless we're starting past it.
fs/xfs/xfs_dir2_sf.c
... ... @@ -557,7 +557,7 @@
557 557 * to insert the new entry.
558 558 * If it's going to end up at the end then oldsfep will point there.
559 559 */
560   - for (offset = XFS_DIR3_DATA_FIRST_OFFSET(mp),
  560 + for (offset = xfs_dir3_data_first_offset(mp),
561 561 oldsfep = xfs_dir2_sf_firstentry(oldsfp),
562 562 add_datasize = xfs_dir3_data_entsize(mp, args->namelen),
563 563 eof = (char *)oldsfep == &buf[old_isize];
... ... @@ -640,7 +640,7 @@
640 640  
641 641 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
642 642 size = xfs_dir3_data_entsize(mp, args->namelen);
643   - offset = XFS_DIR3_DATA_FIRST_OFFSET(mp);
  643 + offset = xfs_dir3_data_first_offset(mp);
644 644 sfep = xfs_dir2_sf_firstentry(sfp);
645 645 holefit = 0;
646 646 /*
... ... @@ -713,7 +713,7 @@
713 713 mp = dp->i_mount;
714 714  
715 715 sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
716   - offset = XFS_DIR3_DATA_FIRST_OFFSET(mp);
  716 + offset = xfs_dir3_data_first_offset(mp);
717 717 ino = xfs_dir2_sf_get_parent_ino(sfp);
718 718 i8count = ino > XFS_DIR2_MAX_SHORT_INUM;
719 719