Re: [PATCH V4] xfs_repair: add support for validating dirent ftype field

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 01/24/2014 05:38 PM, Dave Chinner wrote:
> From: Dave Chinner <dchinner@xxxxxxxxxx>
> 
> Add code to track the filetype of an inode from phase 3 when all the
> inodes are scanned throught to phase 6 when the directory structure
> is validated and corrected.
> 
> Add code to phase 6 shortform and long form directory entry
> validation to read the ftype from the dirent, lookup the inode
> record and check they are the same. If they aren't and we are in
> no-modify mode, issue a warning such as:
> 
> Phase 6 - check inode connectivity...
>         - traversing filesystem ...
> would fix ftype mismatch (5/1) in directory/child inode 64/68
>         - traversal finished ...
>         - moving disconnected inodes to lost+found ...
> 
> If we are fixing the problem:
> 
> Phase 6 - check inode connectivity...
>         - resetting contents of realtime bitmap and summary inodes
>         - traversing filesystem ...
> fixing ftype mismatch (5/1) in directory/child inode 64/68
>         - traversal finished ...
>         - moving disconnected inodes to lost+found ...
> 
> Note that this is from a leaf form directory entry that was
> intentionally corrupted with xfs_db like so:
> 
> xfs_db> inode 64
> xfs_db> a u3.bmx[0].startblock
> xfs_db> p
> ....
> du[3].inumber = 68
> du[3].namelen = 11
> du[3].name = "syscalltest"
> du[3].filetype = 1
> du[3].tag = 0x70
> ....
> xfs_db> write du[3].filetype 5
> du[3].filetype = 5
> xfs_db> quit
> 
> Shortform directory entry repair was tested in a similar fashion.
> 
> Further, track the ftype in the directory hash table that is build,
> so if the directory is rebuild from scratch it has the necessary
> ftype information to rebuild the directory correctly. Further, if we
> detect a ftype mismatch, update the entry in the hash so that later
> directory errors that lead to it being rebuilt use the corrected
> ftype field, not the bad one.
> 
> Note that this code pulls in some kernel side code that is currently
> in kernel private locations (xfs_mode_to_ftype table), so there'll
> be some kernel/userspace sync work needed to bring these back into
> line.
> 
> Signed-off-by: Dave Chinner <dchinner@xxxxxxxxxx>
> 
> Version 4:
> - removed a couple more typedefs
> - fixed no_modify return value from shortform_dir2_junk()
> - cleaned up variable naming, formatting and comments in
>   shortform_dir2_junk() to make it more obvious what it is doing.
> 
> Version 3:
> - fixed max_size updates
> - fixed comment grammar
> 
> Version 2:
> - factored out junking of entry in shortform directory code
> - fixed leak of ftypes array memory
> ---

Looks good. Nice cleanup.

Reviewed-by: Brian Foster <bfoster@xxxxxxxxxx>

>  include/xfs_dir2.h   |   3 +
>  libxfs/xfs_dir2.c    |  16 ++++
>  repair/dino_chunks.c |  11 +++
>  repair/incore.h      |  27 +++++-
>  repair/incore_ino.c  |  30 ++++++-
>  repair/phase6.c      | 246 ++++++++++++++++++++++++++++++++++++---------------
>  repair/scan.c        |   4 +-
>  7 files changed, 258 insertions(+), 79 deletions(-)
> 
> diff --git a/include/xfs_dir2.h b/include/xfs_dir2.h
> index 9910401..3900130 100644
> --- a/include/xfs_dir2.h
> +++ b/include/xfs_dir2.h
> @@ -57,6 +57,9 @@ extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp,
>  extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp,
>  				struct xfs_name *name, uint resblks);
>  
> +#define S_SHIFT 12
> +extern const unsigned char xfs_mode_to_ftype[];
> +
>  /*
>   * Direct call from the bmap code, bypassing the generic directory layer.
>   */
> diff --git a/libxfs/xfs_dir2.c b/libxfs/xfs_dir2.c
> index 96a3c1d..4c8c836 100644
> --- a/libxfs/xfs_dir2.c
> +++ b/libxfs/xfs_dir2.c
> @@ -20,6 +20,22 @@
>  
>  struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR };
>  
> +/*
> + * @mode, if set, indicates that the type field needs to be set up.
> + * This uses the transformation from file mode to DT_* as defined in linux/fs.h
> + * for file type specification. This will be propagated into the directory
> + * structure if appropriate for the given operation and filesystem config.
> + */
> +const unsigned char xfs_mode_to_ftype[S_IFMT >> S_SHIFT] = {
> +	[0]			= XFS_DIR3_FT_UNKNOWN,
> +	[S_IFREG >> S_SHIFT]	= XFS_DIR3_FT_REG_FILE,
> +	[S_IFDIR >> S_SHIFT]	= XFS_DIR3_FT_DIR,
> +	[S_IFCHR >> S_SHIFT]	= XFS_DIR3_FT_CHRDEV,
> +	[S_IFBLK >> S_SHIFT]	= XFS_DIR3_FT_BLKDEV,
> +	[S_IFIFO >> S_SHIFT]	= XFS_DIR3_FT_FIFO,
> +	[S_IFSOCK >> S_SHIFT]	= XFS_DIR3_FT_SOCK,
> +	[S_IFLNK >> S_SHIFT]	= XFS_DIR3_FT_SYMLINK,
> +};
>  
>  /*
>   * ASCII case-insensitive (ie. A-Z) support for directories that was
> diff --git a/repair/dino_chunks.c b/repair/dino_chunks.c
> index d3c2236..65281e4 100644
> --- a/repair/dino_chunks.c
> +++ b/repair/dino_chunks.c
> @@ -788,6 +788,8 @@ process_inode_chunk(
>  		 * we do now, this is where to start.
>  		 */
>  		if (is_used)  {
> +			__uint16_t	di_mode;
> +
>  			if (is_inode_free(ino_rec, irec_offset))  {
>  				if (verbose || no_modify)  {
>  					do_warn(
> @@ -803,6 +805,15 @@ process_inode_chunk(
>  			set_inode_used(ino_rec, irec_offset);
>  
>  			/*
> +			 * store the on-disk file type for comparing in
> +			 * phase 6.
> +			 */
> +			di_mode = be16_to_cpu(dino->di_mode);
> +			di_mode = (di_mode & S_IFMT) >> S_SHIFT;
> +			set_inode_ftype(ino_rec, irec_offset,
> +					xfs_mode_to_ftype[di_mode]);
> +
> +			/*
>  			 * store on-disk nlink count for comparing in phase 7
>  			 */
>  			set_inode_disk_nlinks(ino_rec, irec_offset,
> diff --git a/repair/incore.h b/repair/incore.h
> index 38caa6d..5419884 100644
> --- a/repair/incore.h
> +++ b/repair/incore.h
> @@ -293,6 +293,7 @@ typedef struct ino_tree_node  {
>  		ino_ex_data_t	*ex_data;	/* phases 6,7 */
>  		parent_list_t	*plist;		/* phases 2-5 */
>  	} ino_un;
> +	__uint8_t		*ftypes;	/* phases 3,6 */
>  } ino_tree_node_t;
>  
>  #define INOS_PER_IREC	(sizeof(__uint64_t) * NBBY)
> @@ -359,7 +360,8 @@ ino_tree_node_t		*find_uncertain_inode_rec(xfs_agnumber_t agno,
>  						xfs_agino_t ino);
>  void			add_inode_uncertain(xfs_mount_t *mp,
>  						xfs_ino_t ino, int free);
> -void			add_aginode_uncertain(xfs_agnumber_t agno,
> +void			add_aginode_uncertain(struct xfs_mount *mp,
> +						xfs_agnumber_t agno,
>  						xfs_agino_t agino, int free);
>  void			get_uncertain_inode_rec(struct xfs_mount *mp,
>  						xfs_agnumber_t agno,
> @@ -476,6 +478,29 @@ static inline void add_inode_reached(struct ino_tree_node *irec, int offset)
>  }
>  
>  /*
> + * get/set inode filetype. Only used if the superblock feature bit is set
> + * which allocates irec->ftypes.
> + */
> +static inline void
> +set_inode_ftype(struct ino_tree_node *irec,
> +	int		ino_offset,
> +	__uint8_t	ftype)
> +{
> +	if (irec->ftypes)
> +		irec->ftypes[ino_offset] = ftype;
> +}
> +
> +static inline __uint8_t
> +get_inode_ftype(
> +	struct ino_tree_node *irec,
> +	int		ino_offset)
> +{
> +	if (!irec->ftypes)
> +		return XFS_DIR3_FT_UNKNOWN;
> +	return irec->ftypes[ino_offset];
> +}
> +
> +/*
>   * set/get inode number of parent -- works for directory inodes only
>   */
>  void		set_inode_parent(ino_tree_node_t *irec, int ino_offset,
> diff --git a/repair/incore_ino.c b/repair/incore_ino.c
> index 735737a..9502648 100644
> --- a/repair/incore_ino.c
> +++ b/repair/incore_ino.c
> @@ -211,6 +211,21 @@ __uint32_t get_inode_disk_nlinks(struct ino_tree_node *irec, int ino_offset)
>  	return 0;
>  }
>  
> +static __uint8_t *
> +alloc_ftypes_array(
> +	struct xfs_mount *mp)
> +{
> +	__uint8_t	*ptr;
> +
> +	if (!xfs_sb_version_hasftype(&mp->m_sb))
> +		return NULL;
> +
> +	ptr = calloc(XFS_INODES_PER_CHUNK, sizeof(*ptr));
> +	if (!ptr)
> +		do_error(_("could not allocate ftypes array\n"));
> +	return ptr;
> +}
> +
>  /*
>   * Next is the uncertain inode list -- a sorted (in ascending order)
>   * list of inode records sorted on the starting inode number.  There
> @@ -226,6 +241,7 @@ __uint32_t get_inode_disk_nlinks(struct ino_tree_node *irec, int ino_offset)
>   */
>  static struct ino_tree_node *
>  alloc_ino_node(
> +	struct xfs_mount	*mp,
>  	xfs_agino_t		starting_ino)
>  {
>  	struct ino_tree_node 	*irec;
> @@ -245,6 +261,7 @@ alloc_ino_node(
>  	irec->ino_un.ex_data = NULL;
>  	irec->nlink_size = sizeof(__uint8_t);
>  	irec->disk_nlinks.un8 = alloc_nlink_array(irec->nlink_size);
> +	irec->ftypes = alloc_ftypes_array(mp);
>  	return irec;
>  }
>  
> @@ -285,6 +302,7 @@ free_ino_tree_node(
>  
>  	}
>  
> +	free(irec->ftypes);
>  	free(irec);
>  }
>  
> @@ -303,7 +321,11 @@ static ino_tree_node_t **last_rec;
>   * free is set to 1 if the inode is thought to be free, 0 if used
>   */
>  void
> -add_aginode_uncertain(xfs_agnumber_t agno, xfs_agino_t ino, int free)
> +add_aginode_uncertain(
> +	struct xfs_mount	*mp,
> +	xfs_agnumber_t		agno,
> +	xfs_agino_t		ino,
> +	int			free)
>  {
>  	ino_tree_node_t		*ino_rec;
>  	xfs_agino_t		s_ino;
> @@ -334,7 +356,7 @@ add_aginode_uncertain(xfs_agnumber_t agno, xfs_agino_t ino, int free)
>  	ino_rec = (ino_tree_node_t *)
>  		avl_findrange(inode_uncertain_tree_ptrs[agno], s_ino);
>  	if (!ino_rec) {
> -		ino_rec = alloc_ino_node(s_ino);
> +		ino_rec = alloc_ino_node(mp, s_ino);
>  
>  		if (!avl_insert(inode_uncertain_tree_ptrs[agno],
>  				&ino_rec->avl_node))
> @@ -360,7 +382,7 @@ add_aginode_uncertain(xfs_agnumber_t agno, xfs_agino_t ino, int free)
>  void
>  add_inode_uncertain(xfs_mount_t *mp, xfs_ino_t ino, int free)
>  {
> -	add_aginode_uncertain(XFS_INO_TO_AGNO(mp, ino),
> +	add_aginode_uncertain(mp, XFS_INO_TO_AGNO(mp, ino),
>  				XFS_INO_TO_AGINO(mp, ino), free);
>  }
>  
> @@ -432,7 +454,7 @@ add_inode(
>  {
>  	struct ino_tree_node	*irec;
>  
> -	irec = alloc_ino_node(agino);
> +	irec = alloc_ino_node(mp, agino);
>  	if (!avl_insert(inode_tree_ptrs[agno],	&irec->avl_node))
>  		do_warn(_("add_inode - duplicate inode range\n"));
>  	return irec;
> diff --git a/repair/phase6.c b/repair/phase6.c
> index d2d4a44..cdbf4db 100644
> --- a/repair/phase6.c
> +++ b/repair/phase6.c
> @@ -134,7 +134,8 @@ dir_hash_add(
>  	__uint32_t		addr,
>  	xfs_ino_t		inum,
>  	int			namelen,
> -	unsigned char		*name)
> +	unsigned char		*name,
> +	__uint8_t		ftype)
>  {
>  	xfs_dahash_t		hash = 0;
>  	int			byaddr;
> @@ -148,6 +149,7 @@ dir_hash_add(
>  
>  	xname.name = name;
>  	xname.len = namelen;
> +	xname.type = ftype;
>  
>  	junk = name[0] == '/';
>  	byaddr = DIR_HASH_FUNC(hashtab, addr);
> @@ -312,6 +314,23 @@ dir_hash_see(
>  	return DIR_HASH_CK_NODATA;
>  }
>  
> +static void
> +dir_hash_update_ftype(
> +	dir_hash_tab_t		*hashtab,
> +	xfs_dir2_dataptr_t	addr,
> +	__uint8_t		ftype)
> +{
> +	int			i;
> +	dir_hash_ent_t		*p;
> +
> +	i = DIR_HASH_FUNC(hashtab, addr);
> +	for (p = hashtab->byaddr[i]; p; p = p->nextbyaddr) {
> +		if (p->address != addr)
> +			continue;
> +		p->name.type = ftype;
> +	}
> +}
> +
>  /*
>   * checks to make sure leafs match a data entry, and that the stale
>   * count is valid.
> @@ -1685,11 +1704,12 @@ longform_dir2_entry_check_data(
>  			if (!orphanage_ino)
>  				orphanage_ino = inum;
>  		}
> +
>  		/*
>  		 * check for duplicate names in directory.
>  		 */
>  		if (!dir_hash_add(mp, hashtab, addr, inum, dep->namelen,
> -							dep->name)) {
> +				dep->name, xfs_dir3_dirent_get_ftype(mp, dep))) {
>  			nbad++;
>  			if (entry_junked(
>  	_("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " is a duplicate name"),
> @@ -1763,6 +1783,35 @@ longform_dir2_entry_check_data(
>  		 */
>  		if (no_modify && verify_inum(mp, inum))
>  			continue;
> +
> +		/* validate ftype field if supported */
> +		if (xfs_sb_version_hasftype(&mp->m_sb)) {
> +			__uint8_t dir_ftype;
> +			__uint8_t ino_ftype;
> +
> +			dir_ftype = xfs_dir3_dirent_get_ftype(mp, dep);
> +			ino_ftype = get_inode_ftype(irec, ino_offset);
> +
> +			if (dir_ftype != ino_ftype) {
> +				if (no_modify) {
> +					do_warn(
> +	_("would fix ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"),
> +						dir_ftype, ino_ftype,
> +						ip->i_ino, inum);
> +				} else {
> +					do_warn(
> +	_("fixing ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"),
> +						dir_ftype, ino_ftype,
> +						ip->i_ino, inum);
> +					xfs_dir3_dirent_put_ftype(mp, dep,
> +								ino_ftype);
> +					libxfs_dir2_data_log_entry(tp, bp, dep);
> +					dir_hash_update_ftype(hashtab, addr,
> +							      ino_ftype);
> +				}
> +			}
> +		}
> +
>  		/*
>  		 * check easy case first, regular inode, just bump
>  		 * the link count and continue
> @@ -2189,6 +2238,62 @@ out_fix:
>   * shortform directory v2 processing routines -- entry verification and
>   * bad entry deletion (pruning).
>   */
> +static struct xfs_dir2_sf_entry *
> +shortform_dir2_junk(
> +	struct xfs_mount	*mp,
> +	struct xfs_dir2_sf_hdr	*sfp,
> +	struct xfs_dir2_sf_entry *sfep,
> +	xfs_ino_t		lino,
> +	int			*max_size,
> +	int			*index,
> +	int			*bytes_deleted,
> +	int			*ino_dirty)
> +{
> +	struct xfs_dir2_sf_entry *next_sfep;
> +	int			next_len;
> +	int			next_elen;
> +
> +	if (lino == orphanage_ino)
> +		orphanage_ino = 0;
> +
> +	next_elen = xfs_dir3_sf_entsize(mp, sfp, sfep->namelen);
> +	next_sfep = (xfs_dir2_sf_entry_t *)((__psint_t)sfep + next_elen);
> +
> +	/*
> +	 * if we are just checking, simply return the pointer to the next entry
> +	 * here so that the checking loop can continue.
> +	 */
> +	if (no_modify) {
> +		do_warn(_("would junk entry\n"));
> +		return next_sfep;
> +	}
> +
> +	/*
> +	 * now move all the remaining entries down over the junked entry and
> +	 * clear the newly unused bytes at the tail of the directory region.
> +	 */
> +	next_len = *max_size - ((__psint_t)next_sfep - (__psint_t)sfp);
> +	*max_size -= next_elen;
> +	*bytes_deleted += next_elen;
> +
> +	memmove(sfep, next_sfep, next_len);
> +	memset((void *)((__psint_t)sfep + next_len), 0, next_elen);
> +	sfp->count -= 1;
> +	*ino_dirty = 1;
> +
> +	/*
> +	 * WARNING:  drop the index i by one so it matches the decremented count
> +	 * for accurate comparisons in the loop test
> +	 */
> +	(*index)--;
> +
> +	if (verbose)
> +		do_warn(_("junking entry\n"));
> +	else
> +		do_warn("\n");
> +	return sfep;
> +}
> +
>  static void
>  shortform_dir2_entry_check(xfs_mount_t	*mp,
>  			xfs_ino_t	ino,
> @@ -2201,15 +2306,13 @@ shortform_dir2_entry_check(xfs_mount_t	*mp,
>  	xfs_ino_t		lino;
>  	xfs_ino_t		parent;
>  	struct xfs_dir2_sf_hdr	*sfp;
> -	xfs_dir2_sf_entry_t	*sfep, *next_sfep, *tmp_sfep;
> -	xfs_ifork_t		*ifp;
> -	ino_tree_node_t		*irec;
> +	struct xfs_dir2_sf_entry *sfep;
> +	struct xfs_dir2_sf_entry *next_sfep;
> +	struct xfs_ifork	*ifp;
> +	struct ino_tree_node	*irec;
>  	int			max_size;
>  	int			ino_offset;
>  	int			i;
> -	int			junkit;
> -	int			tmp_len;
> -	int			tmp_elen;
>  	int			bad_sfnamelen;
>  	int			namelen;
>  	int			bytes_deleted;
> @@ -2266,9 +2369,7 @@ shortform_dir2_entry_check(xfs_mount_t	*mp,
>  	for (i = 0; i < sfp->count && max_size >
>  					(__psint_t)next_sfep - (__psint_t)sfp;
>  			sfep = next_sfep, i++)  {
> -		junkit = 0;
>  		bad_sfnamelen = 0;
> -		tmp_sfep = NULL;
>  
>  		lino = xfs_dir3_sfe_get_ino(mp, sfp, sfep);
>  
> @@ -2340,7 +2441,10 @@ shortform_dir2_entry_check(xfs_mount_t	*mp,
>  			do_warn(
>  	_("entry \"%s\" in shortform directory %" PRIu64 " references non-existent inode %" PRIu64 "\n"),
>  				fname, ino, lino);
> -			goto do_junkit;
> +			next_sfep = shortform_dir2_junk(mp, sfp, sfep, lino,
> +						&max_size, &i, &bytes_deleted,
> +						ino_dirty);
> +			continue;
>  		}
>  
>  		ino_offset = XFS_INO_TO_AGINO(mp, lino) - irec->ino_startnum;
> @@ -2354,7 +2458,10 @@ shortform_dir2_entry_check(xfs_mount_t	*mp,
>  			do_warn(
>  	_("entry \"%s\" in shortform directory inode %" PRIu64 " points to free inode %" PRIu64 "\n"),
>  				fname, ino, lino);
> -			goto do_junkit;
> +			next_sfep = shortform_dir2_junk(mp, sfp, sfep, lino,
> +						&max_size, &i, &bytes_deleted,
> +						ino_dirty);
> +			continue;
>  		}
>  		/*
>  		 * check if this inode is lost+found dir in the root
> @@ -2367,7 +2474,10 @@ shortform_dir2_entry_check(xfs_mount_t	*mp,
>  				do_warn(
>  	_("%s (ino %" PRIu64 ") in root (%" PRIu64 ") is not a directory"),
>  					ORPHANAGE, lino, ino);
> -				goto do_junkit;
> +				next_sfep = shortform_dir2_junk(mp, sfp, sfep,
> +						lino, &max_size, &i,
> +						&bytes_deleted, ino_dirty);
> +				continue;
>  			}
>  			/*
>  			 * if this is a dup, it will be picked up below,
> @@ -2381,11 +2491,15 @@ shortform_dir2_entry_check(xfs_mount_t	*mp,
>  		 */
>  		if (!dir_hash_add(mp, hashtab, (xfs_dir2_dataptr_t)
>  				(sfep - xfs_dir2_sf_firstentry(sfp)),
> -				lino, sfep->namelen, sfep->name)) {
> +				lino, sfep->namelen, sfep->name,
> +				xfs_dir3_sfe_get_ftype(mp, sfp, sfep))) {
>  			do_warn(
>  _("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " is a duplicate name"),
>  				fname, lino, ino);
> -			goto do_junkit;
> +			next_sfep = shortform_dir2_junk(mp, sfp, sfep, lino,
> +						&max_size, &i, &bytes_deleted,
> +						ino_dirty);
> +			continue;
>  		}
>  
>  		if (!inode_isadir(irec, ino_offset))  {
> @@ -2403,11 +2517,14 @@ _("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " is a duplicate name"),
>  			 * the .. in the child, blow out the entry
>  			 */
>  			if (is_inode_reached(irec, ino_offset))  {
> -				junkit = 1;
>  				do_warn(
>  	_("entry \"%s\" in directory inode %" PRIu64
>  	  " references already connected inode %" PRIu64 ".\n"),
>  					fname, ino, lino);
> +				next_sfep = shortform_dir2_junk(mp, sfp, sfep,
> +						lino, &max_size, &i,
> +						&bytes_deleted, ino_dirty);
> +				continue;
>  			} else if (parent == ino)  {
>  				add_inode_reached(irec, ino_offset);
>  				add_inode_ref(current_irec, current_ino_offset);
> @@ -2423,76 +2540,60 @@ _("entry \"%s\" (ino %" PRIu64 ") in dir %" PRIu64 " is a duplicate name"),
>  				add_dotdot_update(XFS_INO_TO_AGNO(mp, lino),
>  							irec, ino_offset);
>  			} else  {
> -				junkit = 1;
>  				do_warn(
>  	_("entry \"%s\" in directory inode %" PRIu64
>  	  " not consistent with .. value (%" PRIu64
>  	  ") in inode %" PRIu64 ",\n"),
>  					fname, ino, parent, lino);
> +				next_sfep = shortform_dir2_junk(mp, sfp, sfep,
> +						lino, &max_size, &i,
> +						&bytes_deleted, ino_dirty);
> +				continue;
>  			}
>  		}
>  
> -		if (junkit)  {
> -do_junkit:
> -			if (lino == orphanage_ino)
> -				orphanage_ino = 0;
> -			if (!no_modify)  {
> -				tmp_elen = xfs_dir3_sf_entsize(mp, sfp,
> -								sfep->namelen);
> -				tmp_sfep = (xfs_dir2_sf_entry_t *)
> -					((__psint_t) sfep + tmp_elen);
> -				tmp_len = max_size - ((__psint_t) tmp_sfep
> -							- (__psint_t) sfp);
> -				max_size -= tmp_elen;
> -				bytes_deleted += tmp_elen;
> -
> -				memmove(sfep, tmp_sfep, tmp_len);
> -
> -				sfp->count -= 1;
> -				memset((void *)((__psint_t)sfep + tmp_len), 0,
> -						tmp_elen);
> -
> -				/*
> -				 * set the tmp value to the current
> -				 * pointer so we'll process the entry
> -				 * we just moved up
> -				 */
> -				tmp_sfep = sfep;
> -
> -				/*
> -				 * WARNING:  drop the index i by one
> -				 * so it matches the decremented count for
> -				 * accurate comparisons in the loop test
> -				 */
> -				i--;
> +		/* validate ftype field if supported */
> +		if (xfs_sb_version_hasftype(&mp->m_sb)) {
> +			__uint8_t dir_ftype;
> +			__uint8_t ino_ftype;
>  
> -				*ino_dirty = 1;
> +			dir_ftype = xfs_dir3_sfe_get_ftype(mp, sfp, sfep);
> +			ino_ftype = get_inode_ftype(irec, ino_offset);
>  
> -				if (verbose)
> -					do_warn(_("junking entry\n"));
> -				else
> -					do_warn("\n");
> -			} else  {
> -				do_warn(_("would junk entry\n"));
> +			if (dir_ftype != ino_ftype) {
> +				if (no_modify) {
> +					do_warn(
> +	_("would fix ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"),
> +						dir_ftype, ino_ftype,
> +						ino, lino);
> +				} else {
> +					do_warn(
> +	_("fixing ftype mismatch (%d/%d) in directory/child inode %" PRIu64 "/%" PRIu64 "\n"),
> +						dir_ftype, ino_ftype,
> +						ino, lino);
> +					xfs_dir3_sfe_put_ftype(mp, sfp, sfep,
> +								ino_ftype);
> +					dir_hash_update_ftype(hashtab,
> +			(xfs_dir2_dataptr_t)(sfep - xfs_dir2_sf_firstentry(sfp)),
> +							      ino_ftype);
> +					*ino_dirty = 1;
> +				}
>  			}
> -		} else if (lino > XFS_DIR2_MAX_SHORT_INUM)
> +		}
> +
> +		if (lino > XFS_DIR2_MAX_SHORT_INUM)
>  			i8++;
>  
>  		/*
> -		 * go onto next entry unless we've just junked an
> -		 * entry in which the current entry pointer points
> -		 * to an unprocessed entry.  have to take into entries
> -		 * with bad namelen into account in no modify mode since we
> -		 * calculate size based on next_sfep.
> +		 * go onto next entry - we have to take entries with bad namelen
> +		 * into account in no modify mode since we calculate size based
> +		 * on next_sfep.
>  		 */
>  		ASSERT(no_modify || bad_sfnamelen == 0);
> -
> -		next_sfep = (tmp_sfep == NULL)
> -			? (xfs_dir2_sf_entry_t *) ((__psint_t) sfep
> -							+ ((!bad_sfnamelen)
> -				? xfs_dir3_sf_entsize(mp, sfp, sfep->namelen)
> -				: xfs_dir3_sf_entsize(mp, sfp, namelen)))
> -			: tmp_sfep;
> +		next_sfep = (struct xfs_dir2_sf_entry *)((__psint_t)sfep +
> +			      (bad_sfnamelen
> +				? xfs_dir3_sf_entsize(mp, sfp, namelen)
> +				: xfs_dir3_sf_entsize(mp, sfp, sfep->namelen)));
>  	}
>  
>  	if (sfp->i8count != i8) {
> @@ -2501,6 +2602,8 @@ do_junkit:
>  				ino);
>  		} else {
>  			if (i8 == 0) {
> +				struct xfs_dir2_sf_entry *tmp_sfep;
> +
>  				tmp_sfep = next_sfep;
>  				process_sf_dir2_fixi8(mp, sfp, &tmp_sfep);
>  				bytes_deleted +=
> @@ -2518,8 +2621,7 @@ do_junkit:
>  	/*
>  	 * sync up sizes if required
>  	 */
> -	if (*ino_dirty)  {
> -		ASSERT(bytes_deleted > 0);
> +	if (*ino_dirty && bytes_deleted > 0)  {
>  		ASSERT(!no_modify);
>  		libxfs_idata_realloc(ip, -bytes_deleted, XFS_DATA_FORK);
>  		ip->i_d.di_size -= bytes_deleted;
> diff --git a/repair/scan.c b/repair/scan.c
> index 49ed194..73b4581 100644
> --- a/repair/scan.c
> +++ b/repair/scan.c
> @@ -866,9 +866,9 @@ _("inode rec for ino %" PRIu64 " (%d/%d) overlaps existing rec (start %d/%d)\n")
>  		for (j = 0; j < XFS_INODES_PER_CHUNK; j++) {
>  			if (XFS_INOBT_IS_FREE_DISK(rp, j)) {
>  				nfree++;
> -				add_aginode_uncertain(agno, ino + j, 1);
> +				add_aginode_uncertain(mp, agno, ino + j, 1);
>  			} else  {
> -				add_aginode_uncertain(agno, ino + j, 0);
> +				add_aginode_uncertain(mp, agno, ino + j, 0);
>  			}
>  		}
>  	}
> 

_______________________________________________
xfs mailing list
xfs@xxxxxxxxxxx
http://oss.sgi.com/mailman/listinfo/xfs




[Index of Archives]     [Linux XFS Devel]     [Linux Filesystem Development]     [Filesystem Testing]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux