Esempio n. 1
0
xfs_dir2_leaf_entry_t *
xfs_dir2_block_leaf_p(xfs_dir2_block_tail_t *btp)
{
    return XFS_DIR2_BLOCK_LEAF_P(btp);
}
Esempio n. 2
0
/*
 * Convert a block format directory to shortform.
 * Caller has already checked that it will fit, and built us a header.
 */
int						/* error */
xfs_dir2_block_to_sf(
	xfs_da_args_t		*args,		/* operation arguments */
	xfs_dabuf_t		*bp,		/* block buffer */
	int			size,		/* shortform directory size */
	xfs_dir2_sf_hdr_t	*sfhp)		/* shortform directory hdr */
{
	xfs_dir2_block_t	*block;		/* block structure */
	xfs_dir2_block_tail_t	*btp;		/* block tail pointer */
	xfs_dir2_data_entry_t	*dep;		/* data entry pointer */
	xfs_inode_t		*dp;		/* incore directory inode */
	xfs_dir2_data_unused_t	*dup;		/* unused data pointer */
	char			*endptr;	/* end of data entries */
	int			error;		/* error return value */
	int			logflags;	/* inode logging flags */
	xfs_mount_t		*mp;		/* filesystem mount point */
	char			*ptr;		/* current data pointer */
	xfs_dir2_sf_entry_t	*sfep;		/* shortform entry */
	xfs_dir2_sf_t		*sfp;		/* shortform structure */
	xfs_ino_t               temp;

	xfs_dir2_trace_args_sb("block_to_sf", args, size, bp);
	dp = args->dp;
	mp = dp->i_mount;

	/*
	 * Make a copy of the block data, so we can shrink the inode
	 * and add local data.
	 */
	block = kmem_alloc(mp->m_dirblksize, KM_SLEEP);
	memcpy(block, bp->data, mp->m_dirblksize);
	logflags = XFS_ILOG_CORE;
	if ((error = xfs_dir2_shrink_inode(args, mp->m_dirdatablk, bp))) {
		ASSERT(error != ENOSPC);
		goto out;
	}
	/*
	 * The buffer is now unconditionally gone, whether
	 * xfs_dir2_shrink_inode worked or not.
	 *
	 * Convert the inode to local format.
	 */
	dp->i_df.if_flags &= ~XFS_IFEXTENTS;
	dp->i_df.if_flags |= XFS_IFINLINE;
	dp->i_d.di_format = XFS_DINODE_FMT_LOCAL;
	ASSERT(dp->i_df.if_bytes == 0);
	xfs_idata_realloc(dp, size, XFS_DATA_FORK);
	logflags |= XFS_ILOG_DDATA;
	/*
	 * Copy the header into the newly allocate local space.
	 */
	sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;
	memcpy(sfp, sfhp, XFS_DIR2_SF_HDR_SIZE(sfhp->i8count));
	dp->i_d.di_size = size;
	/*
	 * Set up to loop over the block's entries.
	 */
	btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
	ptr = (char *)block->u;
	endptr = (char *)XFS_DIR2_BLOCK_LEAF_P(btp);
	sfep = XFS_DIR2_SF_FIRSTENTRY(sfp);
	/*
	 * Loop over the active and unused entries.
	 * Stop when we reach the leaf/tail portion of the block.
	 */
	while (ptr < endptr) {
		/*
		 * If it's unused, just skip over it.
		 */
		dup = (xfs_dir2_data_unused_t *)ptr;
		if (INT_GET(dup->freetag, ARCH_CONVERT) == XFS_DIR2_DATA_FREE_TAG) {
			ptr += INT_GET(dup->length, ARCH_CONVERT);
			continue;
		}
		dep = (xfs_dir2_data_entry_t *)ptr;
		/*
		 * Skip .
		 */
		if (dep->namelen == 1 && dep->name[0] == '.')
			ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) == dp->i_ino);
		/*
		 * Skip .., but make sure the inode number is right.
		 */
		else if (dep->namelen == 2 &&
			 dep->name[0] == '.' && dep->name[1] == '.')
			ASSERT(INT_GET(dep->inumber, ARCH_CONVERT) ==
			       XFS_DIR2_SF_GET_INUMBER(sfp, &sfp->hdr.parent));
		/*
		 * Normal entry, copy it into shortform.
		 */
		else {
			sfep->namelen = dep->namelen;
			XFS_DIR2_SF_PUT_OFFSET(sfep,
				(xfs_dir2_data_aoff_t)
				((char *)dep - (char *)block));
			memcpy(sfep->name, dep->name, dep->namelen);
			temp=INT_GET(dep->inumber, ARCH_CONVERT);
			XFS_DIR2_SF_PUT_INUMBER(sfp, &temp,
				XFS_DIR2_SF_INUMBERP(sfep));
			sfep = XFS_DIR2_SF_NEXTENTRY(sfp, sfep);
		}
		ptr += XFS_DIR2_DATA_ENTSIZE(dep->namelen);
	}
	ASSERT((char *)sfep - (char *)sfp == size);
	xfs_dir2_sf_check(args);
out:
	xfs_trans_log_inode(args->trans, dp, logflags);
	kmem_free(block, mp->m_dirblksize);
	return error;
}
Esempio n. 3
0
/*
 * Given a block directory (dp/block), calculate its size as a shortform (sf)
 * directory and a header for the sf directory, if it will fit it the
 * space currently present in the inode.  If it won't fit, the output
 * size is too big (but not accurate).
 */
int						/* size for sf form */
xfs_dir2_block_sfsize(
	xfs_inode_t		*dp,		/* incore inode pointer */
	xfs_dir2_block_t	*block,		/* block directory data */
	xfs_dir2_sf_hdr_t	*sfhp)		/* output: header for sf form */
{
	xfs_dir2_dataptr_t	addr;		/* data entry address */
	xfs_dir2_leaf_entry_t	*blp;		/* leaf area of the block */
	xfs_dir2_block_tail_t	*btp;		/* tail area of the block */
	int			count;		/* shortform entry count */
	xfs_dir2_data_entry_t	*dep;		/* data entry in the block */
	int			i;		/* block entry index */
	int			i8count;	/* count of big-inode entries */
	int			isdot;		/* entry is "." */
	int			isdotdot;	/* entry is ".." */
	xfs_mount_t		*mp;		/* mount structure pointer */
	int			namelen;	/* total name bytes */
	xfs_ino_t		parent = 0;	/* parent inode number */
	int			size=0;		/* total computed size */

	mp = dp->i_mount;

	count = i8count = namelen = 0;
	btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
	blp = XFS_DIR2_BLOCK_LEAF_P(btp);

	/*
	 * Iterate over the block's data entries by using the leaf pointers.
	 */
	for (i = 0; i < INT_GET(btp->count, ARCH_CONVERT); i++) {
		if ((addr = INT_GET(blp[i].address, ARCH_CONVERT)) == XFS_DIR2_NULL_DATAPTR)
			continue;
		/*
		 * Calculate the pointer to the entry at hand.
		 */
		dep = (xfs_dir2_data_entry_t *)
		      ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, addr));
		/*
		 * Detect . and .., so we can special-case them.
		 * . is not included in sf directories.
		 * .. is included by just the parent inode number.
		 */
		isdot = dep->namelen == 1 && dep->name[0] == '.';
		isdotdot =
			dep->namelen == 2 &&
			dep->name[0] == '.' && dep->name[1] == '.';
#if XFS_BIG_INUMS
		if (!isdot)
			i8count += INT_GET(dep->inumber, ARCH_CONVERT) > XFS_DIR2_MAX_SHORT_INUM;
#endif
		if (!isdot && !isdotdot) {
			count++;
			namelen += dep->namelen;
		} else if (isdotdot)
			parent = INT_GET(dep->inumber, ARCH_CONVERT);
		/*
		 * Calculate the new size, see if we should give up yet.
		 */
	/* Add by Jerry 2007/10/25
	   Fixed bug that XFS file system corrupted under Winthrax test.

	   This is the "special" structure alignment on the ARM.
	   Port a workaround solution from a patch on 
			http://lists.arm.linux.org.uk/pipermail/linux-arm-kernel/2004-March/020287.html
			and http://www.nas-central.org/index.php/Buffalo_ARM9_Kernel_Port#XFS_Arm_Issues
	   This patch was never accepted by XFS because the code is incorrect for all other platforms.			
	*/
#if 0
		size = XFS_DIR2_SF_HDR_SIZE(i8count) +		/* header */
		       count +					/* namelen */
		       count * (uint)sizeof(xfs_dir2_sf_off_t) + /* offset */
		       namelen +				/* name */
		       (i8count ?				/* inumber */
				(uint)sizeof(xfs_dir2_ino8_t) * count :
				(uint)sizeof(xfs_dir2_ino4_t) * count);
#else
		size = XFS_DIR2_SF_HDR_SIZE(i8count)		/* header */
				+ namelen
				+ (count * (sizeof(xfs_dir2_sf_entry_t) - 1))
				- (count * (((i8count == 0) ? 1 : 0) *
				(sizeof(xfs_dir2_ino8_t) - sizeof(xfs_dir2_ino4_t))));
#endif
		if (size > XFS_IFORK_DSIZE(dp))
			return size;		/* size value is a failure */
	}
	/*
	 * Create the output header, if it worked.
	 */
	sfhp->count = count;
	sfhp->i8count = i8count;
	XFS_DIR2_SF_PUT_INUMBER((xfs_dir2_sf_t *)sfhp, &parent, &sfhp->parent);
	return size;
}
Esempio n. 4
0
/*
 * Given a block directory (dp/block), calculate its size as a shortform (sf)
 * directory and a header for the sf directory, if it will fit it the
 * space currently present in the inode.  If it won't fit, the output
 * size is too big (but not accurate).
 */
int						/* size for sf form */
xfs_dir2_block_sfsize(
    xfs_inode_t		*dp,		/* incore inode pointer */
    xfs_dir2_block_t	*block,		/* block directory data */
    xfs_dir2_sf_hdr_t	*sfhp)		/* output: header for sf form */
{
    xfs_dir2_dataptr_t	addr;		/* data entry address */
    xfs_dir2_leaf_entry_t	*blp;		/* leaf area of the block */
    xfs_dir2_block_tail_t	*btp;		/* tail area of the block */
    int			count;		/* shortform entry count */
    xfs_dir2_data_entry_t	*dep;		/* data entry in the block */
    int			i;		/* block entry index */
    int			i8count;	/* count of big-inode entries */
    int			isdot;		/* entry is "." */
    int			isdotdot;	/* entry is ".." */
    xfs_mount_t		*mp;		/* mount structure pointer */
    int			namelen;	/* total name bytes */
    xfs_ino_t		parent;		/* parent inode number */
    int			size=0;		/* total computed size */

    mp = dp->i_mount;

    count = i8count = namelen = 0;
    btp = XFS_DIR2_BLOCK_TAIL_P(mp, block);
    blp = XFS_DIR2_BLOCK_LEAF_P(btp);

    /*
     * Iterate over the block's data entries by using the leaf pointers.
     */
    for (i = 0; i < INT_GET(btp->count, ARCH_CONVERT); i++) {
        if ((addr = INT_GET(blp[i].address, ARCH_CONVERT)) == XFS_DIR2_NULL_DATAPTR)
            continue;
        /*
         * Calculate the pointer to the entry at hand.
         */
        dep = (xfs_dir2_data_entry_t *)
              ((char *)block + XFS_DIR2_DATAPTR_TO_OFF(mp, addr));
        /*
         * Detect . and .., so we can special-case them.
         * . is not included in sf directories.
         * .. is included by just the parent inode number.
         */
        isdot = dep->namelen == 1 && dep->name[0] == '.';
        isdotdot =
            dep->namelen == 2 &&
            dep->name[0] == '.' && dep->name[1] == '.';
#if XFS_BIG_INUMS
        if (!isdot)
            i8count += INT_GET(dep->inumber, ARCH_CONVERT) > XFS_DIR2_MAX_SHORT_INUM;
#endif
        if (!isdot && !isdotdot) {
            count++;
            namelen += dep->namelen;
        } else if (isdotdot)
            parent = INT_GET(dep->inumber, ARCH_CONVERT);
        /*
         * Calculate the new size, see if we should give up yet.
         */
        size = XFS_DIR2_SF_HDR_SIZE(i8count) +		/* header */
               count +					/* namelen */
               count * (uint)sizeof(xfs_dir2_sf_off_t) + /* offset */
               namelen +				/* name */
               (i8count ?				/* inumber */
                (uint)sizeof(xfs_dir2_ino8_t) * count :
                (uint)sizeof(xfs_dir2_ino4_t) * count);
        if (size > XFS_IFORK_DSIZE(dp))
            return size;		/* size value is a failure */
    }
    /*
     * Create the output header, if it worked.
     */
    sfhp->count = count;
    sfhp->i8count = i8count;
    XFS_DIR2_SF_PUT_INUMBER((xfs_dir2_sf_t *)sfhp, &parent, &sfhp->parent);
    return size;
}