xfs_attr_leaf.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,154 行 · 第 1/5 页

C
2,154
字号
{	attrlist_cursor_kern_t *cursor;	xfs_attr_sf_sort_t *sbuf, *sbp;	xfs_attr_shortform_t *sf;	xfs_attr_sf_entry_t *sfe;	xfs_inode_t *dp;	int sbsize, nsbuf, count, i;	ASSERT(context != NULL);	dp = context->dp;	ASSERT(dp != NULL);	ASSERT(dp->i_afp != NULL);	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;	ASSERT(sf != NULL);	if (INT_ISZERO(sf->hdr.count, ARCH_CONVERT))		return(0);	cursor = context->cursor;	ASSERT(cursor != NULL);	xfs_attr_trace_l_c("sf start", context);	/*	 * If the buffer is large enough, do not bother with sorting.	 * Note the generous fudge factor of 16 overhead bytes per entry.	 */	if ((dp->i_afp->if_bytes + INT_GET(sf->hdr.count, ARCH_CONVERT) * 16)							< context->bufsize) {		for (i = 0, sfe = &sf->list[0];				i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) {			attrnames_t	*namesp;			if (((context->flags & ATTR_SECURE) != 0) !=			    ((sfe->flags & XFS_ATTR_SECURE) != 0) &&			    !(context->flags & ATTR_KERNORMALS)) {				sfe = XFS_ATTR_SF_NEXTENTRY(sfe);				continue;			}			if (((context->flags & ATTR_ROOT) != 0) !=			    ((sfe->flags & XFS_ATTR_ROOT) != 0) &&			    !(context->flags & ATTR_KERNROOTLS)) {				sfe = XFS_ATTR_SF_NEXTENTRY(sfe);				continue;			}			namesp = (sfe->flags & XFS_ATTR_SECURE) ? &attr_secure:				((sfe->flags & XFS_ATTR_ROOT) ? &attr_trusted :				  &attr_user);			if (context->flags & ATTR_KERNOVAL) {				ASSERT(context->flags & ATTR_KERNAMELS);				context->count += namesp->attr_namelen +					INT_GET(sfe->namelen, ARCH_CONVERT) + 1;			}			else {				if (xfs_attr_put_listent(context, namesp,						   (char *)sfe->nameval,						   (int)sfe->namelen,						   (int)INT_GET(sfe->valuelen,								ARCH_CONVERT)))					break;			}			sfe = XFS_ATTR_SF_NEXTENTRY(sfe);		}		xfs_attr_trace_l_c("sf big-gulp", context);		return(0);	}	/*	 * It didn't all fit, so we have to sort everything on hashval.	 */	sbsize = INT_GET(sf->hdr.count, ARCH_CONVERT) * sizeof(*sbuf);	sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP);	/*	 * Scan the attribute list for the rest of the entries, storing	 * the relevant info from only those that match into a buffer.	 */	nsbuf = 0;	for (i = 0, sfe = &sf->list[0];			i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) {		if (unlikely(		    ((char *)sfe < (char *)sf) ||		    ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)))) {			XFS_CORRUPTION_ERROR("xfs_attr_shortform_list",					     XFS_ERRLEVEL_LOW,					     context->dp->i_mount, sfe);			xfs_attr_trace_l_c("sf corrupted", context);			kmem_free(sbuf, sbsize);			return XFS_ERROR(EFSCORRUPTED);		}		if (((context->flags & ATTR_SECURE) != 0) !=		    ((sfe->flags & XFS_ATTR_SECURE) != 0) &&		    !(context->flags & ATTR_KERNORMALS)) {			sfe = XFS_ATTR_SF_NEXTENTRY(sfe);			continue;		}		if (((context->flags & ATTR_ROOT) != 0) !=		    ((sfe->flags & XFS_ATTR_ROOT) != 0) &&		    !(context->flags & ATTR_KERNROOTLS)) {			sfe = XFS_ATTR_SF_NEXTENTRY(sfe);			continue;		}		sbp->entno = i;		INT_SET(sbp->hash, ARCH_CONVERT,			xfs_da_hashname((char *)sfe->nameval, sfe->namelen));		sbp->name = (char *)sfe->nameval;		sbp->namelen = sfe->namelen;		/* These are bytes, and both on-disk, don't endian-flip */		sbp->valuelen = sfe->valuelen;		sbp->flags = sfe->flags;		sfe = XFS_ATTR_SF_NEXTENTRY(sfe);		sbp++;		nsbuf++;	}	/*	 * Sort the entries on hash then entno.	 */	qsort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare);	/*	 * Re-find our place IN THE SORTED LIST.	 */	count = 0;	cursor->initted = 1;	cursor->blkno = 0;	for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) {		if (INT_GET(sbp->hash, ARCH_CONVERT) == cursor->hashval) {			if (cursor->offset == count) {				break;			}			count++;		} else if (INT_GET(sbp->hash, ARCH_CONVERT) > cursor->hashval) {			break;		}	}	if (i == nsbuf) {		kmem_free(sbuf, sbsize);		xfs_attr_trace_l_c("blk end", context);		return(0);	}	/*	 * Loop putting entries into the user buffer.	 */	for ( ; i < nsbuf; i++, sbp++) {		attrnames_t	*namesp;		namesp = (sbp->flags & XFS_ATTR_SECURE) ? &attr_secure :			((sbp->flags & XFS_ATTR_ROOT) ? &attr_trusted :			  &attr_user);		if (cursor->hashval != INT_GET(sbp->hash, ARCH_CONVERT)) {			cursor->hashval = INT_GET(sbp->hash, ARCH_CONVERT);			cursor->offset = 0;		}		if (context->flags & ATTR_KERNOVAL) {			ASSERT(context->flags & ATTR_KERNAMELS);			context->count += namesp->attr_namelen +						sbp->namelen + 1;		} else {			if (xfs_attr_put_listent(context, namesp,					sbp->name, sbp->namelen,					INT_GET(sbp->valuelen, ARCH_CONVERT)))				break;		}		cursor->offset++;	}	kmem_free(sbuf, sbsize);	xfs_attr_trace_l_c("sf E-O-F", context);	return(0);}/* * Check a leaf attribute block to see if all the entries would fit into * a shortform attribute list. */intxfs_attr_shortform_allfit(xfs_dabuf_t *bp, xfs_inode_t *dp){	xfs_attr_leafblock_t *leaf;	xfs_attr_leaf_entry_t *entry;	xfs_attr_leaf_name_local_t *name_loc;	int bytes, i;	leaf = bp->data;	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)						== XFS_ATTR_LEAF_MAGIC);	entry = &leaf->entries[0];	bytes = sizeof(struct xfs_attr_sf_hdr);	for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) {		if (entry->flags & XFS_ATTR_INCOMPLETE)			continue;		/* don't copy partial entries */		if (!(entry->flags & XFS_ATTR_LOCAL))			return(0);		name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);		if (name_loc->namelen >= XFS_ATTR_SF_ENTSIZE_MAX)			return(0);		if (INT_GET(name_loc->valuelen, ARCH_CONVERT) >= XFS_ATTR_SF_ENTSIZE_MAX)			return(0);		bytes += sizeof(struct xfs_attr_sf_entry)-1				+ name_loc->namelen				+ INT_GET(name_loc->valuelen, ARCH_CONVERT);	}	return( bytes < XFS_IFORK_ASIZE(dp) );}/* * Convert a leaf attribute list to shortform attribute list */intxfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args){	xfs_attr_leafblock_t *leaf;	xfs_attr_leaf_entry_t *entry;	xfs_attr_leaf_name_local_t *name_loc;	xfs_da_args_t nargs;	xfs_inode_t *dp;	char *tmpbuffer;	int error, i;	dp = args->dp;	tmpbuffer = kmem_alloc(XFS_LBSIZE(dp->i_mount), KM_SLEEP);	ASSERT(tmpbuffer != NULL);	ASSERT(bp != NULL);	memcpy(tmpbuffer, bp->data, XFS_LBSIZE(dp->i_mount));	leaf = (xfs_attr_leafblock_t *)tmpbuffer;	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)						== XFS_ATTR_LEAF_MAGIC);	memset(bp->data, 0, XFS_LBSIZE(dp->i_mount));	/*	 * Clean out the prior contents of the attribute list.	 */	error = xfs_da_shrink_inode(args, 0, bp);	if (error)		goto out;	error = xfs_attr_shortform_create(args);	if (error)		goto out;	/*	 * Copy the attributes	 */	memset((char *)&nargs, 0, sizeof(nargs));	nargs.dp = dp;	nargs.firstblock = args->firstblock;	nargs.flist = args->flist;	nargs.total = args->total;	nargs.whichfork = XFS_ATTR_FORK;	nargs.trans = args->trans;	nargs.oknoent = 1;	entry = &leaf->entries[0];	for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) {		if (entry->flags & XFS_ATTR_INCOMPLETE)			continue;	/* don't copy partial entries */		if (INT_ISZERO(entry->nameidx, ARCH_CONVERT))			continue;		ASSERT(entry->flags & XFS_ATTR_LOCAL);		name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);		nargs.name = (char *)name_loc->nameval;		nargs.namelen = name_loc->namelen;		nargs.value = (char *)&name_loc->nameval[nargs.namelen];		nargs.valuelen = INT_GET(name_loc->valuelen, ARCH_CONVERT);		nargs.hashval = INT_GET(entry->hashval, ARCH_CONVERT);		nargs.flags = (entry->flags & XFS_ATTR_SECURE) ? ATTR_SECURE :			      ((entry->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);		xfs_attr_shortform_add(&nargs);	}	error = 0;out:	kmem_free(tmpbuffer, XFS_LBSIZE(dp->i_mount));	return(error);}/* * Convert from using a single leaf to a root node and a leaf. */intxfs_attr_leaf_to_node(xfs_da_args_t *args){	xfs_attr_leafblock_t *leaf;	xfs_da_intnode_t *node;	xfs_inode_t *dp;	xfs_dabuf_t *bp1, *bp2;	xfs_dablk_t blkno;	int error;	dp = args->dp;	bp1 = bp2 = NULL;	error = xfs_da_grow_inode(args, &blkno);	if (error)		goto out;	error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp1,					     XFS_ATTR_FORK);	if (error)		goto out;	ASSERT(bp1 != NULL);	bp2 = NULL;	error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp2,					    XFS_ATTR_FORK);	if (error)		goto out;	ASSERT(bp2 != NULL);	memcpy(bp2->data, bp1->data, XFS_LBSIZE(dp->i_mount));	xfs_da_buf_done(bp1);	bp1 = NULL;	xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1);	/*	 * Set up the new root node.	 */	error = xfs_da_node_create(args, 0, 1, &bp1, XFS_ATTR_FORK);	if (error)		goto out;	node = bp1->data;	leaf = bp2->data;	ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)						== XFS_ATTR_LEAF_MAGIC);	/* both on-disk, don't endian-flip twice */	node->btree[0].hashval =		leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval;	INT_SET(node->btree[0].before, ARCH_CONVERT, blkno);	INT_SET(node->hdr.count, ARCH_CONVERT, 1);	xfs_da_log_buf(args->trans, bp1, 0, XFS_LBSIZE(dp->i_mount) - 1);	error = 0;out:	if (bp1)		xfs_da_buf_done(bp1);	if (bp2)		xfs_da_buf_done(bp2);	return(error);}/*======================================================================== * Routines used for growing the Btree. *========================================================================*//* * Create the initial contents of a leaf attribute list * or a leaf in a node attribute list. */intxfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp){	xfs_attr_leafblock_t *leaf;	xfs_attr_leaf_hdr_t *hdr;	xfs_inode_t *dp;	xfs_dabuf_t *bp;	int error;	dp = args->dp;	ASSERT(dp != NULL);	error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp,					    XFS_ATTR_FORK);	if (error)		return(error);	ASSERT(bp != NULL);	leaf = bp->data;	memset((char *)leaf, 0, XFS_LBSIZE(dp->i_mount));	hdr = &leaf->hdr;	INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_ATTR_LEAF_MAGIC);	INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount));	if (INT_ISZERO(hdr->firstused, ARCH_CONVERT)) {		INT_SET(hdr->firstused, ARCH_CONVERT,			XFS_LBSIZE(dp->i_mount) - XFS_ATTR_LEAF_NAME_ALIGN);	}	INT_SET(hdr->freemap[0].base, ARCH_CONVERT,						sizeof(xfs_attr_leaf_hdr_t));	INT_SET(hdr->freemap[0].size, ARCH_CONVERT,					  INT_GET(hdr->firstused, ARCH_CONVERT)					- INT_GET(hdr->freemap[0].base,								ARCH_CONVERT));	xfs_da_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1);	*bpp = bp;	return(0);}/* * Split the leaf node, rebalance, then add the new entry. */intxfs_attr_leaf_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,				   xfs_da_state_blk_t *newblk){	xfs_dablk_t blkno;	int error;	/*	 * Allocate space for a new leaf node.	 */	ASSERT(oldblk->magic == XFS_ATTR_LEAF_MAGIC);	error = xfs_da_grow_inode(state->args, &blkno);	if (error)		return(error);	error = xfs_attr_leaf_create(state->args, blkno, &newblk->bp);	if (error)		return(error);	newblk->blkno = blkno;	newblk->magic = XFS_ATTR_LEAF_MAGIC;	/*	 * Rebalance the entries across the two leaves.	 * NOTE: rebalance() currently depends on the 2nd block being empty.	 */	xfs_attr_leaf_rebalance(state, oldblk, newblk);	error = xfs_da_blk_link(state, oldblk, newblk);	if (error)		return(error);	/*	 * Save info on "old" attribute for "atomic rename" ops, leaf_add()	 * modifies the index/blkno/rmtblk/rmtblkcnt fields to show the	 * "new" attrs info.  Will need the "old" info to remove it later.	 *	 * Insert the "new" entry in the correct block.	 */	if (state->inleaf)		error = xfs_attr_leaf_add(oldblk->bp, state->args);	else		error = xfs_attr_leaf_add(newblk->bp, state->args);	/*	 * Update last hashval in each block since we added the name.	 */

⌨️ 快捷键说明

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