Commit 726801ba authored by Tim Shimmin's avatar Tim Shimmin
Browse files

[XFS] Add EA list callbacks for xfs kernel use. Cleanup some namespace


code.

SGI-PV: 954372
SGI-Modid: xfs-linux-melb:xfs-kern:26583a

Signed-off-by: default avatarTim Shimmin <tes@sgi.com>
parent 69e23b9a
Loading
Loading
Loading
Loading
+141 −40
Original line number Diff line number Diff line
@@ -91,7 +91,6 @@ STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
/*
 * Routines to manipulate out-of-line attribute values.
 */
STATIC int xfs_attr_rmtval_get(xfs_da_args_t *args);
STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args);
STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args);

@@ -180,7 +179,7 @@ xfs_attr_get(bhv_desc_t *bdp, const char *name, char *value, int *valuelenp,
	return(error);
}

STATIC int
int
xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen,
		 char *value, int valuelen, int flags)
{
@@ -440,7 +439,7 @@ xfs_attr_set(bhv_desc_t *bdp, const char *name, char *value, int valuelen, int f
 * Generic handler routine to remove a name from an attribute list.
 * Transitions attribute list from Btree to shortform as necessary.
 */
STATIC int
int
xfs_attr_remove_int(xfs_inode_t *dp, const char *name, int namelen, int flags)
{
	xfs_da_args_t	args;
@@ -591,6 +590,110 @@ xfs_attr_remove(bhv_desc_t *bdp, const char *name, int flags, struct cred *cred)
	return xfs_attr_remove_int(dp, name, namelen, flags);
}

int								/* error */
xfs_attr_list_int(xfs_attr_list_context_t *context)
{
	int error;
	xfs_inode_t *dp = context->dp;

	/*
	 * Decide on what work routines to call based on the inode size.
	 */
	if (XFS_IFORK_Q(dp) == 0 ||
	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
	     dp->i_d.di_anextents == 0)) {
		error = 0;
	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
		error = xfs_attr_shortform_list(context);
	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
		error = xfs_attr_leaf_list(context);
	} else {
		error = xfs_attr_node_list(context);
	}
	return error;
}

#define	ATTR_ENTBASESIZE		/* minimum bytes used by an attr */ \
	(((struct attrlist_ent *) 0)->a_name - (char *) 0)
#define	ATTR_ENTSIZE(namelen)		/* actual bytes used by an attr */ \
	((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \
	 & ~(sizeof(u_int32_t)-1))

/*
 * Format an attribute and copy it out to the user's buffer.
 * Take care to check values and protect against them changing later,
 * we may be reading them directly out of a user buffer.
 */
/*ARGSUSED*/
STATIC int
xfs_attr_put_listent(xfs_attr_list_context_t *context, attrnames_t *namesp,
		     char *name, int namelen,
		     int valuelen, char *value)
{
	attrlist_ent_t *aep;
	int arraytop;

	ASSERT(!(context->flags & ATTR_KERNOVAL));
	ASSERT(context->count >= 0);
	ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
	ASSERT(context->firstu >= sizeof(*context->alist));
	ASSERT(context->firstu <= context->bufsize);

	arraytop = sizeof(*context->alist) +
			context->count * sizeof(context->alist->al_offset[0]);
	context->firstu -= ATTR_ENTSIZE(namelen);
	if (context->firstu < arraytop) {
		xfs_attr_trace_l_c("buffer full", context);
		context->alist->al_more = 1;
		context->seen_enough = 1;
		return 1;
	}

	aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]);
	aep->a_valuelen = valuelen;
	memcpy(aep->a_name, name, namelen);
	aep->a_name[ namelen ] = 0;
	context->alist->al_offset[ context->count++ ] = context->firstu;
	context->alist->al_count = context->count;
	xfs_attr_trace_l_c("add", context);
	return 0;
}

STATIC int
xfs_attr_kern_list(xfs_attr_list_context_t *context, attrnames_t *namesp,
		     char *name, int namelen,
		     int valuelen, char *value)
{
	char *offset;
	int arraytop;

	ASSERT(context->count >= 0);

	arraytop = context->count + namesp->attr_namelen + namelen + 1;
	if (arraytop > context->firstu) {
		context->count = -1;	/* insufficient space */
		return 1;
	}
	offset = (char *)context->alist + context->count;
	strncpy(offset, namesp->attr_name, namesp->attr_namelen);
	offset += namesp->attr_namelen;
	strncpy(offset, name, namelen);			/* real name */
	offset += namelen;
	*offset = '\0';
	context->count += namesp->attr_namelen + namelen + 1;
	return 0;
}

/*ARGSUSED*/
STATIC int
xfs_attr_kern_list_sizes(xfs_attr_list_context_t *context, attrnames_t *namesp,
		     char *name, int namelen,
		     int valuelen, char *value)
{
	context->count += namesp->attr_namelen + namelen + 1;
	return 0;
}

/*
 * Generate a list of extended attribute names and optionally
 * also value lengths.  Positive return value follows the XFS
@@ -615,13 +718,13 @@ xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags,
		return(XFS_ERROR(EINVAL));
	if ((cursor->initted == 0) &&
	    (cursor->hashval || cursor->blkno || cursor->offset))
		return(XFS_ERROR(EINVAL));
		return XFS_ERROR(EINVAL);

	/*
	 * Check for a properly aligned buffer.
	 */
	if (((long)buffer) & (sizeof(int)-1))
		return(XFS_ERROR(EFAULT));
		return XFS_ERROR(EFAULT);
	if (flags & ATTR_KERNOVAL)
		bufsize = 0;

@@ -634,53 +737,47 @@ xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags,
	context.dupcnt = 0;
	context.resynch = 1;
	context.flags = flags;
	if (!(flags & ATTR_KERNAMELS)) {
	context.seen_enough = 0;
	context.alist = (attrlist_t *)buffer;
	context.put_value = 0;

	if (flags & ATTR_KERNAMELS) {
		context.bufsize = bufsize;
		context.firstu = context.bufsize;
		if (flags & ATTR_KERNOVAL)
			context.put_listent = xfs_attr_kern_list_sizes;
		else
			context.put_listent = xfs_attr_kern_list;
	} else {
		context.bufsize = (bufsize & ~(sizeof(int)-1));  /* align */
		context.firstu = context.bufsize;
		context.alist = (attrlist_t *)buffer;
		context.alist->al_count = 0;
		context.alist->al_more = 0;
		context.alist->al_offset[0] = context.bufsize;
	}
	else {
		context.bufsize = bufsize;
		context.firstu = context.bufsize;
		context.alist = (attrlist_t *)buffer;
		context.put_listent = xfs_attr_put_listent;
	}

	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
		return (EIO);
		return EIO;

	xfs_ilock(dp, XFS_ILOCK_SHARED);
	/*
	 * Decide on what work routines to call based on the inode size.
	 */
	xfs_attr_trace_l_c("syscall start", &context);
	if (XFS_IFORK_Q(dp) == 0 ||
	    (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
	     dp->i_d.di_anextents == 0)) {
		error = 0;
	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
		error = xfs_attr_shortform_list(&context);
	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
		error = xfs_attr_leaf_list(&context);
	} else {
		error = xfs_attr_node_list(&context);
	}

	error = xfs_attr_list_int(&context);

	xfs_iunlock(dp, XFS_ILOCK_SHARED);
	xfs_attr_trace_l_c("syscall end", &context);

	if (!(context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS))) {
		ASSERT(error >= 0);
	}
	else {	/* must return negated buffer size or the error */
	if (context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS)) {
		/* must return negated buffer size or the error */
		if (context.count < 0)
			error = XFS_ERROR(ERANGE);
		else
			error = -context.count;
	}
	} else
		ASSERT(error >= 0);

	return(error);
	return error;
}

int								/* error */
@@ -1122,19 +1219,19 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context)
	context->cursor->blkno = 0;
	error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK);
	if (error)
		return(error);
		return XFS_ERROR(error);
	ASSERT(bp != NULL);
	leaf = bp->data;
	if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC)) {
		XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW,
				     context->dp->i_mount, leaf);
		xfs_da_brelse(NULL, bp);
		return(XFS_ERROR(EFSCORRUPTED));
		return XFS_ERROR(EFSCORRUPTED);
	}

	(void)xfs_attr_leaf_list_int(bp, context);
	error = xfs_attr_leaf_list_int(bp, context);
	xfs_da_brelse(NULL, bp);
	return(0);
	return XFS_ERROR(error);
}


@@ -1858,8 +1955,12 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
			return(XFS_ERROR(EFSCORRUPTED));
		}
		error = xfs_attr_leaf_list_int(bp, context);
		if (error || !leaf->hdr.info.forw)
			break;	/* not really an error, buffer full or EOF */
		if (error) {
			xfs_da_brelse(NULL, bp);
			return error;
		}
		if (context->seen_enough || leaf->hdr.info.forw == 0)
			break;
		cursor->blkno = be32_to_cpu(leaf->hdr.info.forw);
		xfs_da_brelse(NULL, bp);
		error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1,
@@ -1886,7 +1987,7 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
 * Read the value associated with an attribute from the out-of-line buffer
 * that we stored it in.
 */
STATIC int
int
xfs_attr_rmtval_get(xfs_da_args_t *args)
{
	xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE];
+6 −2
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@

struct cred;
struct bhv_vnode;
struct xfs_attr_list_context;

typedef int (*attrset_t)(struct bhv_vnode *, char *, void *, size_t, int);
typedef int (*attrget_t)(struct bhv_vnode *, char *, void *, size_t, int);
@@ -160,13 +161,16 @@ struct xfs_da_args;
 */
int xfs_attr_get(bhv_desc_t *, const char *, char *, int *, int, struct cred *);
int xfs_attr_set(bhv_desc_t *, const char *, char *, int, int, struct cred *);
int xfs_attr_set_int(struct xfs_inode *, const char *, int, char *, int, int);
int xfs_attr_remove(bhv_desc_t *, const char *, int, struct cred *);
int xfs_attr_list(bhv_desc_t *, char *, int, int,
			 struct attrlist_cursor_kern *, struct cred *);
int xfs_attr_remove_int(struct xfs_inode *, const char *, int, int);
int xfs_attr_list(bhv_desc_t *, char *, int, int, struct attrlist_cursor_kern *, struct cred *);
int xfs_attr_list_int(struct xfs_attr_list_context *);
int xfs_attr_inactive(struct xfs_inode *dp);

int xfs_attr_shortform_getvalue(struct xfs_da_args *);
int xfs_attr_fetch(struct xfs_inode *, const char *, int,
			char *, int *, int, struct cred *);
int xfs_attr_rmtval_get(struct xfs_da_args *args);

#endif	/* __XFS_ATTR_H__ */
+155 −196
Original line number Diff line number Diff line
@@ -89,9 +89,46 @@ STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf,
					 int dst_start, int move_count,
					 xfs_mount_t *mp);
STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index);
STATIC int xfs_attr_put_listent(xfs_attr_list_context_t *context,
			     attrnames_t *, char *name, int namelen,
			     int valuelen);

/*========================================================================
 * Namespace helper routines
 *========================================================================*/

STATIC inline attrnames_t *
xfs_attr_flags_namesp(int flags)
{
	return ((flags & XFS_ATTR_SECURE) ? &attr_secure:
		  ((flags & XFS_ATTR_ROOT) ? &attr_trusted : &attr_user));
}

/*
 * If namespace bits don't match return 0.
 * If all match then return 1.
 */
STATIC inline int
xfs_attr_namesp_match(int arg_flags, int ondisk_flags)
{
	return XFS_ATTR_NSP_ONDISK(ondisk_flags) == XFS_ATTR_NSP_ARGS_TO_ONDISK(arg_flags);
}

/*
 * If namespace bits don't match and we don't have an override for it
 * then return 0.
 * If all match or are overridable then return 1.
 */
STATIC inline int
xfs_attr_namesp_match_overrides(int arg_flags, int ondisk_flags)
{
	if (((arg_flags & ATTR_SECURE) == 0) !=
	    ((ondisk_flags & XFS_ATTR_SECURE) == 0) &&
	    !(arg_flags & ATTR_KERNORMALS))
		return 0;
	if (((arg_flags & ATTR_ROOT) == 0) !=
	    ((ondisk_flags & XFS_ATTR_ROOT) == 0) &&
	    !(arg_flags & ATTR_KERNROOTLS))
		return 0;
	return 1;
}


/*========================================================================
@@ -228,11 +265,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
			continue;
		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
			continue;
		if (((args->flags & ATTR_SECURE) != 0) !=
		    ((sfe->flags & XFS_ATTR_SECURE) != 0))
			continue;
		if (((args->flags & ATTR_ROOT) != 0) !=
		    ((sfe->flags & XFS_ATTR_ROOT) != 0))
		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
			continue;
		ASSERT(0);
#endif
@@ -246,8 +279,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)

	sfe->namelen = args->namelen;
	sfe->valuelen = args->valuelen;
	sfe->flags = (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE :
			((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0);
	sfe->flags = XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
	memcpy(sfe->nameval, args->name, args->namelen);
	memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen);
	sf->hdr.count++;
@@ -282,11 +314,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
			continue;
		if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
			continue;
		if (((args->flags & ATTR_SECURE) != 0) !=
		    ((sfe->flags & XFS_ATTR_SECURE) != 0))
			continue;
		if (((args->flags & ATTR_ROOT) != 0) !=
		    ((sfe->flags & XFS_ATTR_ROOT) != 0))
		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
			continue;
		break;
	}
@@ -363,11 +391,7 @@ xfs_attr_shortform_lookup(xfs_da_args_t *args)
			continue;
		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
			continue;
		if (((args->flags & ATTR_SECURE) != 0) !=
		    ((sfe->flags & XFS_ATTR_SECURE) != 0))
			continue;
		if (((args->flags & ATTR_ROOT) != 0) !=
		    ((sfe->flags & XFS_ATTR_ROOT) != 0))
		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
			continue;
		return(XFS_ERROR(EEXIST));
	}
@@ -394,11 +418,7 @@ xfs_attr_shortform_getvalue(xfs_da_args_t *args)
			continue;
		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
			continue;
		if (((args->flags & ATTR_SECURE) != 0) !=
		    ((sfe->flags & XFS_ATTR_SECURE) != 0))
			continue;
		if (((args->flags & ATTR_ROOT) != 0) !=
		    ((sfe->flags & XFS_ATTR_ROOT) != 0))
		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
			continue;
		if (args->flags & ATTR_KERNOVAL) {
			args->valuelen = sfe->valuelen;
@@ -485,8 +505,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
		nargs.valuelen = sfe->valuelen;
		nargs.hashval = xfs_da_hashname((char *)sfe->nameval,
						sfe->namelen);
		nargs.flags = (sfe->flags & XFS_ATTR_SECURE) ? ATTR_SECURE :
				((sfe->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);
		nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(sfe->flags);
		error = xfs_attr_leaf_lookup_int(bp, &nargs); /* set a->index */
		ASSERT(error == ENOATTR);
		error = xfs_attr_leaf_add(bp, &nargs);
@@ -520,6 +539,10 @@ xfs_attr_shortform_compare(const void *a, const void *b)
	}
}


#define XFS_ISRESET_CURSOR(cursor) \
	(!((cursor)->initted) && !((cursor)->hashval) && \
	 !((cursor)->blkno) && !((cursor)->offset))
/*
 * Copy out entries of shortform attribute lists for attr_list().
 * Shortform attribute lists are not stored in hashval sorted order.
@@ -537,6 +560,7 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
	xfs_attr_sf_entry_t *sfe;
	xfs_inode_t *dp;
	int sbsize, nsbuf, count, i;
	int error;

	ASSERT(context != NULL);
	dp = context->dp;
@@ -552,46 +576,51 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
	xfs_attr_trace_l_c("sf start", context);

	/*
	 * If the buffer is large enough, do not bother with sorting.
	 * If the buffer is large enough and the cursor is at the start,
	 * do not bother with sorting since we will return everything in
	 * one buffer and another call using the cursor won't need to be
	 * made.
	 * Note the generous fudge factor of 16 overhead bytes per entry.
	 * If bufsize is zero then put_listent must be a search function
	 * and can just scan through what we have.
	 */
	if ((dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize) {
	if (context->bufsize == 0 ||
	    (XFS_ISRESET_CURSOR(cursor) &&
             (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) {
		for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; 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)) {
			if (!xfs_attr_namesp_match_overrides(context->flags, sfe->flags)) {
				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 +
					sfe->namelen + 1;
			}
			else {
				if (xfs_attr_put_listent(context, namesp,
			namesp = xfs_attr_flags_namesp(sfe->flags);
			error = context->put_listent(context,
					   namesp,
					   (char *)sfe->nameval,
					   (int)sfe->namelen,
						   (int)sfe->valuelen))
					   (int)sfe->valuelen,
					   (char*)&sfe->nameval[sfe->namelen]);

			/*
			 * Either search callback finished early or
			 * didn't fit it all in the buffer after all.
			 */
			if (context->seen_enough)
				break;
			}

			if (error)
				return error;
			sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
		}
		xfs_attr_trace_l_c("sf big-gulp", context);
		return(0);
	}

	/* do no more for a search callback */
	if (context->bufsize == 0)
		return 0;

	/*
	 * It didn't all fit, so we have to sort everything on hashval.
	 */
@@ -614,15 +643,7 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *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)) {
		if (!xfs_attr_namesp_match_overrides(context->flags, sfe->flags)) {
			sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
			continue;
		}
@@ -671,24 +692,22 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
	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);
		namesp = xfs_attr_flags_namesp(sbp->flags);

		if (cursor->hashval != sbp->hash) {
			cursor->hashval = sbp->hash;
			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,
					sbp->valuelen))
		error = context->put_listent(context,
					namesp,
					sbp->name,
					sbp->namelen,
					sbp->valuelen,
					&sbp->name[sbp->namelen]);
		if (error)
			return error;
		if (context->seen_enough)
			break;
		}
		cursor->offset++;
	}

@@ -810,8 +829,7 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff)
		nargs.value = (char *)&name_loc->nameval[nargs.namelen];
		nargs.valuelen = be16_to_cpu(name_loc->valuelen);
		nargs.hashval = be32_to_cpu(entry->hashval);
		nargs.flags = (entry->flags & XFS_ATTR_SECURE) ? ATTR_SECURE :
			      ((entry->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);
		nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags);
		xfs_attr_shortform_add(&nargs, forkoff);
	}
	error = 0;
@@ -1098,8 +1116,7 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex)
				     be16_to_cpu(map->size));
	entry->hashval = cpu_to_be32(args->hashval);
	entry->flags = tmp ? XFS_ATTR_LOCAL : 0;
	entry->flags |= (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE :
			((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0);
	entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
	if (args->rename) {
		entry->flags |= XFS_ATTR_INCOMPLETE;
		if ((args->blkno2 == args->blkno) &&
@@ -1971,14 +1988,9 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args)
			name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, probe);
			if (name_loc->namelen != args->namelen)
				continue;
			if (memcmp(args->name, (char *)name_loc->nameval,
					     args->namelen) != 0)
				continue;
			if (((args->flags & ATTR_SECURE) != 0) !=
			    ((entry->flags & XFS_ATTR_SECURE) != 0))
			if (memcmp(args->name, (char *)name_loc->nameval, args->namelen) != 0)
				continue;
			if (((args->flags & ATTR_ROOT) != 0) !=
			    ((entry->flags & XFS_ATTR_ROOT) != 0))
			if (!xfs_attr_namesp_match(args->flags, entry->flags))
				continue;
			args->index = probe;
			return(XFS_ERROR(EEXIST));
@@ -1989,11 +2001,7 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args)
			if (memcmp(args->name, (char *)name_rmt->name,
					     args->namelen) != 0)
				continue;
			if (((args->flags & ATTR_SECURE) != 0) !=
			    ((entry->flags & XFS_ATTR_SECURE) != 0))
				continue;
			if (((args->flags & ATTR_ROOT) != 0) !=
			    ((entry->flags & XFS_ATTR_ROOT) != 0))
			if (!xfs_attr_namesp_match(args->flags, entry->flags))
				continue;
			args->index = probe;
			args->rmtblkno = be32_to_cpu(name_rmt->valueblk);
@@ -2312,8 +2320,6 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
	attrlist_cursor_kern_t *cursor;
	xfs_attr_leafblock_t *leaf;
	xfs_attr_leaf_entry_t *entry;
	xfs_attr_leaf_name_local_t *name_loc;
	xfs_attr_leaf_name_remote_t *name_rmt;
	int retval, i;

	ASSERT(bp != NULL);
@@ -2355,8 +2361,7 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
	 * We have found our place, start copying out the new attributes.
	 */
	retval = 0;
	for (  ; (i < be16_to_cpu(leaf->hdr.count))
	     && (retval == 0); entry++, i++) {
	for (  ; (i < be16_to_cpu(leaf->hdr.count)); entry++, i++) {
		attrnames_t *namesp;

		if (be32_to_cpu(entry->hashval) != cursor->hashval) {
@@ -2366,115 +2371,69 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)

		if (entry->flags & XFS_ATTR_INCOMPLETE)
			continue;		/* skip incomplete entries */
		if (((context->flags & ATTR_SECURE) != 0) !=
		    ((entry->flags & XFS_ATTR_SECURE) != 0) &&
		    !(context->flags & ATTR_KERNORMALS))
			continue;		/* skip non-matching entries */
		if (((context->flags & ATTR_ROOT) != 0) !=
		    ((entry->flags & XFS_ATTR_ROOT) != 0) &&
		    !(context->flags & ATTR_KERNROOTLS))
			continue;		/* skip non-matching entries */

		namesp = (entry->flags & XFS_ATTR_SECURE) ? &attr_secure :
			((entry->flags & XFS_ATTR_ROOT) ? &attr_trusted :
			  &attr_user);
		if (!xfs_attr_namesp_match_overrides(context->flags, entry->flags))
			continue;

		namesp = xfs_attr_flags_namesp(entry->flags);

		if (entry->flags & XFS_ATTR_LOCAL) {
			name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
			if (context->flags & ATTR_KERNOVAL) {
				ASSERT(context->flags & ATTR_KERNAMELS);
				context->count += namesp->attr_namelen +
						(int)name_loc->namelen + 1;
			} else {
				retval = xfs_attr_put_listent(context, namesp,
			xfs_attr_leaf_name_local_t *name_loc =
				XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);

			retval = context->put_listent(context,
						namesp,
						(char *)name_loc->nameval,
						(int)name_loc->namelen,
					be16_to_cpu(name_loc->valuelen));
			}
						be16_to_cpu(name_loc->valuelen),
						(char *)&name_loc->nameval[name_loc->namelen]);
			if (retval)
				return retval;
		} else {
			name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
			if (context->flags & ATTR_KERNOVAL) {
				ASSERT(context->flags & ATTR_KERNAMELS);
				context->count += namesp->attr_namelen +
						(int)name_rmt->namelen + 1;
			} else {
				retval = xfs_attr_put_listent(context, namesp,
			xfs_attr_leaf_name_remote_t *name_rmt =
				XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);

			int valuelen = be32_to_cpu(name_rmt->valuelen);

			if (context->put_value) {
				xfs_da_args_t args;

				memset((char *)&args, 0, sizeof(args));
				args.dp = context->dp;
				args.whichfork = XFS_ATTR_FORK;
				args.valuelen = valuelen;
				args.value = kmem_alloc(valuelen, KM_SLEEP);
				args.rmtblkno = be32_to_cpu(name_rmt->valueblk);
				args.rmtblkcnt = XFS_B_TO_FSB(args.dp->i_mount, valuelen);
				retval = xfs_attr_rmtval_get(&args);
				if (retval)
					return retval;
				retval = context->put_listent(context,
						namesp,
						(char *)name_rmt->name,
						(int)name_rmt->namelen,
					be32_to_cpu(name_rmt->valuelen));
						valuelen,
						(char*)args.value);
				kmem_free(args.value, valuelen);
			}
			else {
				retval = context->put_listent(context,
						namesp,
						(char *)name_rmt->name,
						(int)name_rmt->namelen,
						valuelen,
						NULL);
			}
		if (retval == 0) {
			cursor->offset++;
			if (retval)
				return retval;
		}
		if (context->seen_enough)
			break;
		cursor->offset++;
	}
	xfs_attr_trace_l_cl("blk end", context, leaf);
	return(retval);
}

#define	ATTR_ENTBASESIZE		/* minimum bytes used by an attr */ \
	(((struct attrlist_ent *) 0)->a_name - (char *) 0)
#define	ATTR_ENTSIZE(namelen)		/* actual bytes used by an attr */ \
	((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \
	 & ~(sizeof(u_int32_t)-1))

/*
 * Format an attribute and copy it out to the user's buffer.
 * Take care to check values and protect against them changing later,
 * we may be reading them directly out of a user buffer.
 */
/*ARGSUSED*/
STATIC int
xfs_attr_put_listent(xfs_attr_list_context_t *context,
		     attrnames_t *namesp, char *name, int namelen, int valuelen)
{
	attrlist_ent_t *aep;
	int arraytop;

	ASSERT(!(context->flags & ATTR_KERNOVAL));
	if (context->flags & ATTR_KERNAMELS) {
		char *offset;

		ASSERT(context->count >= 0);

		arraytop = context->count + namesp->attr_namelen + namelen + 1;
		if (arraytop > context->firstu) {
			context->count = -1;	/* insufficient space */
			return(1);
		}
		offset = (char *)context->alist + context->count;
		strncpy(offset, namesp->attr_name, namesp->attr_namelen);
		offset += namesp->attr_namelen;
		strncpy(offset, name, namelen);			/* real name */
		offset += namelen;
		*offset = '\0';
		context->count += namesp->attr_namelen + namelen + 1;
		return(0);
	}

	ASSERT(context->count >= 0);
	ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
	ASSERT(context->firstu >= sizeof(*context->alist));
	ASSERT(context->firstu <= context->bufsize);

	arraytop = sizeof(*context->alist) +
			context->count * sizeof(context->alist->al_offset[0]);
	context->firstu -= ATTR_ENTSIZE(namelen);
	if (context->firstu < arraytop) {
		xfs_attr_trace_l_c("buffer full", context);
		context->alist->al_more = 1;
		return(1);
	}

	aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]);
	aep->a_valuelen = valuelen;
	memcpy(aep->a_name, name, namelen);
	aep->a_name[ namelen ] = 0;
	context->alist->al_offset[ context->count++ ] = context->firstu;
	context->alist->al_count = context->count;
	xfs_attr_trace_l_c("add", context);
	return(0);
}

/*========================================================================
 * Manage the INCOMPLETE flag in a leaf entry
+32 −9

File changed.

Preview size limit exceeded, changes collapsed.