⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xfs_dir2_block.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	int			ent;		/* leaf entry index */	int			error;		/* error return value */	xfs_mount_t		*mp;		/* filesystem mount point */	xfs_dir2_trace_args("block_replace", args);	/*	 * Lookup the entry in the directory.  Get buffer and entry index.	 * This will always succeed since the caller has already done a lookup.	 */	if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) {		return error;	}	dp = args->dp;	mp = dp->i_mount;	block = bp->data;	btp = xfs_dir2_block_tail_p(mp, block);	blp = xfs_dir2_block_leaf_p(btp);	/*	 * Point to the data entry we need to change.	 */	dep = (xfs_dir2_data_entry_t *)	      ((char *)block + xfs_dir2_dataptr_to_off(mp, be32_to_cpu(blp[ent].address)));	ASSERT(be64_to_cpu(dep->inumber) != args->inumber);	/*	 * Change the inode number to the new value.	 */	dep->inumber = cpu_to_be64(args->inumber);	xfs_dir2_data_log_entry(args->trans, bp, dep);	xfs_dir2_data_check(dp, bp);	xfs_da_buf_done(bp);	return 0;}/* * Qsort comparison routine for the block leaf entries. */static int					/* sort order */xfs_dir2_block_sort(	const void			*a,	/* first leaf entry */	const void			*b)	/* second leaf entry */{	const xfs_dir2_leaf_entry_t	*la;	/* first leaf entry */	const xfs_dir2_leaf_entry_t	*lb;	/* second leaf entry */	la = a;	lb = b;	return be32_to_cpu(la->hashval) < be32_to_cpu(lb->hashval) ? -1 :		(be32_to_cpu(la->hashval) > be32_to_cpu(lb->hashval) ? 1 : 0);}/* * Convert a V2 leaf directory to a V2 block directory if possible. */int						/* error */xfs_dir2_leaf_to_block(	xfs_da_args_t		*args,		/* operation arguments */	xfs_dabuf_t		*lbp,		/* leaf buffer */	xfs_dabuf_t		*dbp)		/* data buffer */{	__be16			*bestsp;	/* leaf bests table */	xfs_dir2_block_t	*block;		/* block structure */	xfs_dir2_block_tail_t	*btp;		/* block tail */	xfs_inode_t		*dp;		/* incore directory inode */	xfs_dir2_data_unused_t	*dup;		/* unused data entry */	int			error;		/* error return value */	int			from;		/* leaf from index */	xfs_dir2_leaf_t		*leaf;		/* leaf structure */	xfs_dir2_leaf_entry_t	*lep;		/* leaf entry */	xfs_dir2_leaf_tail_t	*ltp;		/* leaf tail structure */	xfs_mount_t		*mp;		/* file system mount point */	int			needlog;	/* need to log data header */	int			needscan;	/* need to scan for bestfree */	xfs_dir2_sf_hdr_t	sfh;		/* shortform header */	int			size;		/* bytes used */	__be16			*tagp;		/* end of entry (tag) */	int			to;		/* block/leaf to index */	xfs_trans_t		*tp;		/* transaction pointer */	xfs_dir2_trace_args_bb("leaf_to_block", args, lbp, dbp);	dp = args->dp;	tp = args->trans;	mp = dp->i_mount;	leaf = lbp->data;	ASSERT(be16_to_cpu(leaf->hdr.info.magic) == XFS_DIR2_LEAF1_MAGIC);	ltp = xfs_dir2_leaf_tail_p(mp, leaf);	/*	 * If there are data blocks other than the first one, take this	 * opportunity to remove trailing empty data blocks that may have	 * been left behind during no-space-reservation operations.	 * These will show up in the leaf bests table.	 */	while (dp->i_d.di_size > mp->m_dirblksize) {		bestsp = xfs_dir2_leaf_bests_p(ltp);		if (be16_to_cpu(bestsp[be32_to_cpu(ltp->bestcount) - 1]) ==		    mp->m_dirblksize - (uint)sizeof(block->hdr)) {			if ((error =			    xfs_dir2_leaf_trim_data(args, lbp,				    (xfs_dir2_db_t)(be32_to_cpu(ltp->bestcount) - 1))))				goto out;		} else {			error = 0;			goto out;		}	}	/*	 * Read the data block if we don't already have it, give up if it fails.	 */	if (dbp == NULL &&	    (error = xfs_da_read_buf(tp, dp, mp->m_dirdatablk, -1, &dbp,		    XFS_DATA_FORK))) {		goto out;	}	block = dbp->data;	ASSERT(be32_to_cpu(block->hdr.magic) == XFS_DIR2_DATA_MAGIC);	/*	 * Size of the "leaf" area in the block.	 */	size = (uint)sizeof(block->tail) +	       (uint)sizeof(*lep) * (be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale));	/*	 * Look at the last data entry.	 */	tagp = (__be16 *)((char *)block + mp->m_dirblksize) - 1;	dup = (xfs_dir2_data_unused_t *)((char *)block + be16_to_cpu(*tagp));	/*	 * If it's not free or is too short we can't do it.	 */	if (be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG ||	    be16_to_cpu(dup->length) < size) {		error = 0;		goto out;	}	/*	 * Start converting it to block form.	 */	block->hdr.magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC);	needlog = 1;	needscan = 0;	/*	 * Use up the space at the end of the block (blp/btp).	 */	xfs_dir2_data_use_free(tp, dbp, dup, mp->m_dirblksize - size, size,		&needlog, &needscan);	/*	 * Initialize the block tail.	 */	btp = xfs_dir2_block_tail_p(mp, block);	btp->count = cpu_to_be32(be16_to_cpu(leaf->hdr.count) - be16_to_cpu(leaf->hdr.stale));	btp->stale = 0;	xfs_dir2_block_log_tail(tp, dbp);	/*	 * Initialize the block leaf area.  We compact out stale entries.	 */	lep = xfs_dir2_block_leaf_p(btp);	for (from = to = 0; from < be16_to_cpu(leaf->hdr.count); from++) {		if (be32_to_cpu(leaf->ents[from].address) == XFS_DIR2_NULL_DATAPTR)			continue;		lep[to++] = leaf->ents[from];	}	ASSERT(to == be32_to_cpu(btp->count));	xfs_dir2_block_log_leaf(tp, dbp, 0, be32_to_cpu(btp->count) - 1);	/*	 * Scan the bestfree if we need it and log the data block header.	 */	if (needscan)		xfs_dir2_data_freescan(mp, (xfs_dir2_data_t *)block, &needlog);	if (needlog)		xfs_dir2_data_log_header(tp, dbp);	/*	 * Pitch the old leaf block.	 */	error = xfs_da_shrink_inode(args, mp->m_dirleafblk, lbp);	lbp = NULL;	if (error) {		goto out;	}	/*	 * Now see if the resulting block can be shrunken to shortform.	 */	if ((size = xfs_dir2_block_sfsize(dp, block, &sfh)) >	    XFS_IFORK_DSIZE(dp)) {		error = 0;		goto out;	}	return xfs_dir2_block_to_sf(args, dbp, size, &sfh);out:	if (lbp)		xfs_da_buf_done(lbp);	if (dbp)		xfs_da_buf_done(dbp);	return error;}/* * Convert the shortform directory to block form. */int						/* error */xfs_dir2_sf_to_block(	xfs_da_args_t		*args)		/* operation arguments */{	xfs_dir2_db_t		blkno;		/* dir-relative block # (0) */	xfs_dir2_block_t	*block;		/* block structure */	xfs_dir2_leaf_entry_t	*blp;		/* block leaf entries */	xfs_dabuf_t		*bp;		/* block buffer */	xfs_dir2_block_tail_t	*btp;		/* block tail pointer */	char			*buf;		/* sf buffer */	int			buf_len;	xfs_dir2_data_entry_t	*dep;		/* data entry pointer */	xfs_inode_t		*dp;		/* incore directory inode */	int			dummy;		/* trash */	xfs_dir2_data_unused_t	*dup;		/* unused entry pointer */	int			endoffset;	/* end of data objects */	int			error;		/* error return value */	int			i;		/* index */	xfs_mount_t		*mp;		/* filesystem mount point */	int			needlog;	/* need to log block header */	int			needscan;	/* need to scan block freespc */	int			newoffset;	/* offset from current entry */	int			offset;		/* target block offset */	xfs_dir2_sf_entry_t	*sfep;		/* sf entry pointer */	xfs_dir2_sf_t		*sfp;		/* shortform structure */	__be16			*tagp;		/* end of data entry */	xfs_trans_t		*tp;		/* transaction pointer */	xfs_dir2_trace_args("sf_to_block", args);	dp = args->dp;	tp = args->trans;	mp = dp->i_mount;	ASSERT(dp->i_df.if_flags & XFS_IFINLINE);	/*	 * Bomb out if the shortform directory is way too short.	 */	if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) {		ASSERT(XFS_FORCED_SHUTDOWN(mp));		return XFS_ERROR(EIO);	}	ASSERT(dp->i_df.if_bytes == dp->i_d.di_size);	ASSERT(dp->i_df.if_u1.if_data != NULL);	sfp = (xfs_dir2_sf_t *)dp->i_df.if_u1.if_data;	ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->hdr.i8count));	/*	 * Copy the directory into the stack buffer.	 * Then pitch the incore inode data so we can make extents.	 */	buf_len = dp->i_df.if_bytes;	buf = kmem_alloc(dp->i_df.if_bytes, KM_SLEEP);	memcpy(buf, sfp, dp->i_df.if_bytes);	xfs_idata_realloc(dp, -dp->i_df.if_bytes, XFS_DATA_FORK);	dp->i_d.di_size = 0;	xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);	/*	 * Reset pointer - old sfp is gone.	 */	sfp = (xfs_dir2_sf_t *)buf;	/*	 * Add block 0 to the inode.	 */	error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno);	if (error) {		kmem_free(buf, buf_len);		return error;	}	/*	 * Initialize the data block.	 */	error = xfs_dir2_data_init(args, blkno, &bp);	if (error) {		kmem_free(buf, buf_len);		return error;	}	block = bp->data;	block->hdr.magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC);	/*	 * Compute size of block "tail" area.	 */	i = (uint)sizeof(*btp) +	    (sfp->hdr.count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t);	/*	 * The whole thing is initialized to free by the init routine.	 * Say we're using the leaf and tail area.	 */	dup = (xfs_dir2_data_unused_t *)block->u;	needlog = needscan = 0;	xfs_dir2_data_use_free(tp, bp, dup, mp->m_dirblksize - i, i, &needlog,		&needscan);	ASSERT(needscan == 0);	/*	 * Fill in the tail.	 */	btp = xfs_dir2_block_tail_p(mp, block);	btp->count = cpu_to_be32(sfp->hdr.count + 2);	/* ., .. */	btp->stale = 0;	blp = xfs_dir2_block_leaf_p(btp);	endoffset = (uint)((char *)blp - (char *)block);	/*	 * Remove the freespace, we'll manage it.	 */	xfs_dir2_data_use_free(tp, bp, dup,		(xfs_dir2_data_aoff_t)((char *)dup - (char *)block),		be16_to_cpu(dup->length), &needlog, &needscan);	/*	 * Create entry for .	 */	dep = (xfs_dir2_data_entry_t *)	      ((char *)block + XFS_DIR2_DATA_DOT_OFFSET);	dep->inumber = cpu_to_be64(dp->i_ino);	dep->namelen = 1;	dep->name[0] = '.';	tagp = xfs_dir2_data_entry_tag_p(dep);	*tagp = cpu_to_be16((char *)dep - (char *)block);	xfs_dir2_data_log_entry(tp, bp, dep);	blp[0].hashval = cpu_to_be32(xfs_dir_hash_dot);	blp[0].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,				(char *)dep - (char *)block));	/*	 * Create entry for ..	 */	dep = (xfs_dir2_data_entry_t *)		((char *)block + XFS_DIR2_DATA_DOTDOT_OFFSET);	dep->inumber = cpu_to_be64(xfs_dir2_sf_get_inumber(sfp, &sfp->hdr.parent));	dep->namelen = 2;	dep->name[0] = dep->name[1] = '.';	tagp = xfs_dir2_data_entry_tag_p(dep);	*tagp = cpu_to_be16((char *)dep - (char *)block);	xfs_dir2_data_log_entry(tp, bp, dep);	blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot);	blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,				(char *)dep - (char *)block));	offset = XFS_DIR2_DATA_FIRST_OFFSET;	/*	 * Loop over existing entries, stuff them in.	 */	if ((i = 0) == sfp->hdr.count)		sfep = NULL;	else		sfep = xfs_dir2_sf_firstentry(sfp);	/*	 * Need to preserve the existing offset values in the sf directory.	 * Insert holes (unused entries) where necessary.	 */	while (offset < endoffset) {		/*		 * sfep is null when we reach the end of the list.		 */		if (sfep == NULL)			newoffset = endoffset;		else			newoffset = xfs_dir2_sf_get_offset(sfep);		/*		 * There should be a hole here, make one.		 */		if (offset < newoffset) {			dup = (xfs_dir2_data_unused_t *)			      ((char *)block + offset);			dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG);			dup->length = cpu_to_be16(newoffset - offset);			*xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16(				((char *)dup - (char *)block));			xfs_dir2_data_log_unused(tp, bp, dup);			(void)xfs_dir2_data_freeinsert((xfs_dir2_data_t *)block,				dup, &dummy);			offset += be16_to_cpu(dup->length);			continue;		}		/*		 * Copy a real entry.		 */		dep = (xfs_dir2_data_entry_t *)((char *)block + newoffset);		dep->inumber = cpu_to_be64(xfs_dir2_sf_get_inumber(sfp,				xfs_dir2_sf_inumberp(sfep)));		dep->namelen = sfep->namelen;		memcpy(dep->name, sfep->name, dep->namelen);		tagp = xfs_dir2_data_entry_tag_p(dep);		*tagp = cpu_to_be16((char *)dep - (char *)block);		xfs_dir2_data_log_entry(tp, bp, dep);		blp[2 + i].hashval = cpu_to_be32(xfs_da_hashname(					(char *)sfep->name, sfep->namelen));		blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr(mp,						 (char *)dep - (char *)block));		offset = (int)((char *)(tagp + 1) - (char *)block);		if (++i == sfp->hdr.count)			sfep = NULL;		else			sfep = xfs_dir2_sf_nextentry(sfp, sfep);	}	/* Done with the temporary buffer */	kmem_free(buf, buf_len);	/*	 * Sort the leaf entries by hash value.	 */	xfs_sort(blp, be32_to_cpu(btp->count), sizeof(*blp), xfs_dir2_block_sort);	/*	 * Log the leaf entry area and tail.	 * Already logged the header in data_init, ignore needlog.	 */	ASSERT(needscan == 0);	xfs_dir2_block_log_leaf(tp, bp, 0, be32_to_cpu(btp->count) - 1);	xfs_dir2_block_log_tail(tp, bp);	xfs_dir2_data_check(dp, bp);	xfs_da_buf_done(bp);	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -