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

[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
...@@ -91,7 +91,6 @@ STATIC int xfs_attr_refillstate(xfs_da_state_t *state); ...@@ -91,7 +91,6 @@ STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
/* /*
* Routines to manipulate out-of-line attribute values. * 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_set(xfs_da_args_t *args);
STATIC int xfs_attr_rmtval_remove(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, ...@@ -180,7 +179,7 @@ xfs_attr_get(bhv_desc_t *bdp, const char *name, char *value, int *valuelenp,
return(error); return(error);
} }
STATIC int int
xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen, xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen,
char *value, int valuelen, int flags) 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 ...@@ -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. * Generic handler routine to remove a name from an attribute list.
* Transitions attribute list from Btree to shortform as necessary. * 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_attr_remove_int(xfs_inode_t *dp, const char *name, int namelen, int flags)
{ {
xfs_da_args_t args; xfs_da_args_t args;
...@@ -591,6 +590,110 @@ xfs_attr_remove(bhv_desc_t *bdp, const char *name, int flags, struct cred *cred) ...@@ -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); 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 * Generate a list of extended attribute names and optionally
* also value lengths. Positive return value follows the XFS * 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, ...@@ -615,13 +718,13 @@ xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags,
return(XFS_ERROR(EINVAL)); return(XFS_ERROR(EINVAL));
if ((cursor->initted == 0) && if ((cursor->initted == 0) &&
(cursor->hashval || cursor->blkno || cursor->offset)) (cursor->hashval || cursor->blkno || cursor->offset))
return(XFS_ERROR(EINVAL)); return XFS_ERROR(EINVAL);
/* /*
* Check for a properly aligned buffer. * Check for a properly aligned buffer.
*/ */
if (((long)buffer) & (sizeof(int)-1)) if (((long)buffer) & (sizeof(int)-1))
return(XFS_ERROR(EFAULT)); return XFS_ERROR(EFAULT);
if (flags & ATTR_KERNOVAL) if (flags & ATTR_KERNOVAL)
bufsize = 0; bufsize = 0;
...@@ -634,53 +737,47 @@ xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags, ...@@ -634,53 +737,47 @@ xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags,
context.dupcnt = 0; context.dupcnt = 0;
context.resynch = 1; context.resynch = 1;
context.flags = flags; 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.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */
context.firstu = context.bufsize; context.firstu = context.bufsize;
context.alist = (attrlist_t *)buffer;
context.alist->al_count = 0; context.alist->al_count = 0;
context.alist->al_more = 0; context.alist->al_more = 0;
context.alist->al_offset[0] = context.bufsize; context.alist->al_offset[0] = context.bufsize;
} context.put_listent = xfs_attr_put_listent;
else {
context.bufsize = bufsize;
context.firstu = context.bufsize;
context.alist = (attrlist_t *)buffer;
} }
if (XFS_FORCED_SHUTDOWN(dp->i_mount)) if (XFS_FORCED_SHUTDOWN(dp->i_mount))
return (EIO); return EIO;
xfs_ilock(dp, XFS_ILOCK_SHARED); 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); xfs_attr_trace_l_c("syscall start", &context);
if (XFS_IFORK_Q(dp) == 0 ||
(dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && error = xfs_attr_list_int(&context);
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);
}
xfs_iunlock(dp, XFS_ILOCK_SHARED); xfs_iunlock(dp, XFS_ILOCK_SHARED);
xfs_attr_trace_l_c("syscall end", &context); xfs_attr_trace_l_c("syscall end", &context);
if (!(context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS))) { if (context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS)) {
ASSERT(error >= 0); /* must return negated buffer size or the error */
}
else { /* must return negated buffer size or the error */
if (context.count < 0) if (context.count < 0)
error = XFS_ERROR(ERANGE); error = XFS_ERROR(ERANGE);
else else
error = -context.count; error = -context.count;
} } else
ASSERT(error >= 0);
return(error); return error;
} }
int /* error */ int /* error */
...@@ -1122,19 +1219,19 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context) ...@@ -1122,19 +1219,19 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context)
context->cursor->blkno = 0; context->cursor->blkno = 0;
error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK); error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK);
if (error) if (error)
return(error); return XFS_ERROR(error);
ASSERT(bp != NULL); ASSERT(bp != NULL);
leaf = bp->data; leaf = bp->data;
if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC)) { if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC)) {
XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW, XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW,
context->dp->i_mount, leaf); context->dp->i_mount, leaf);
xfs_da_brelse(NULL, bp); 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); 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) ...@@ -1858,8 +1955,12 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
return(XFS_ERROR(EFSCORRUPTED)); return(XFS_ERROR(EFSCORRUPTED));
} }
error = xfs_attr_leaf_list_int(bp, context); error = xfs_attr_leaf_list_int(bp, context);
if (error || !leaf->hdr.info.forw) if (error) {
break; /* not really an error, buffer full or EOF */ 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); cursor->blkno = be32_to_cpu(leaf->hdr.info.forw);
xfs_da_brelse(NULL, bp); xfs_da_brelse(NULL, bp);
error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1, 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) ...@@ -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 * Read the value associated with an attribute from the out-of-line buffer
* that we stored it in. * that we stored it in.
*/ */
STATIC int int
xfs_attr_rmtval_get(xfs_da_args_t *args) xfs_attr_rmtval_get(xfs_da_args_t *args)
{ {
xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE]; xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE];
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
struct cred; struct cred;
struct bhv_vnode; struct bhv_vnode;
struct xfs_attr_list_context;
typedef int (*attrset_t)(struct bhv_vnode *, char *, void *, size_t, int); typedef int (*attrset_t)(struct bhv_vnode *, char *, void *, size_t, int);
typedef int (*attrget_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; ...@@ -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_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(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_remove(bhv_desc_t *, const char *, int, struct cred *);
int xfs_attr_list(bhv_desc_t *, char *, int, int, int xfs_attr_remove_int(struct xfs_inode *, const char *, int, int);
struct attrlist_cursor_kern *, struct cred *); 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_inactive(struct xfs_inode *dp);
int xfs_attr_shortform_getvalue(struct xfs_da_args *); int xfs_attr_shortform_getvalue(struct xfs_da_args *);
int xfs_attr_fetch(struct xfs_inode *, const char *, int, int xfs_attr_fetch(struct xfs_inode *, const char *, int,
char *, int *, int, struct cred *); char *, int *, int, struct cred *);
int xfs_attr_rmtval_get(struct xfs_da_args *args);
#endif /* __XFS_ATTR_H__ */ #endif /* __XFS_ATTR_H__ */
...@@ -89,9 +89,46 @@ STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf, ...@@ -89,9 +89,46 @@ STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf,
int dst_start, int move_count, int dst_start, int move_count,
xfs_mount_t *mp); xfs_mount_t *mp);
STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index); 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) ...@@ -228,11 +265,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
continue; continue;
if (memcmp(args->name, sfe->nameval, args->namelen) != 0) if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
continue; continue;
if (((args->flags & ATTR_SECURE) != 0) != if (!xfs_attr_namesp_match(args->flags, sfe->flags))
((sfe->flags & XFS_ATTR_SECURE) != 0))
continue;
if (((args->flags & ATTR_ROOT) != 0) !=
((sfe->flags & XFS_ATTR_ROOT) != 0))
continue; continue;
ASSERT(0); ASSERT(0);
#endif #endif
...@@ -246,8 +279,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff) ...@@ -246,8 +279,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
sfe->namelen = args->namelen; sfe->namelen = args->namelen;
sfe->valuelen = args->valuelen; sfe->valuelen = args->valuelen;
sfe->flags = (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE : sfe->flags = XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0);
memcpy(sfe->nameval, args->name, args->namelen); memcpy(sfe->nameval, args->name, args->namelen);
memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen); memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen);
sf->hdr.count++; sf->hdr.count++;
...@@ -282,11 +314,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args) ...@@ -282,11 +314,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
continue; continue;
if (memcmp(sfe->nameval, args->name, args->namelen) != 0) if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
continue; continue;
if (((args->flags & ATTR_SECURE) != 0) != if (!xfs_attr_namesp_match(args->flags, sfe->flags))
((sfe->flags & XFS_ATTR_SECURE) != 0))
continue;
if (((args->flags & ATTR_ROOT) != 0) !=
((sfe->flags & XFS_ATTR_ROOT) != 0))
continue; continue;
break; break;
} }
...@@ -363,11 +391,7 @@ xfs_attr_shortform_lookup(xfs_da_args_t *args) ...@@ -363,11 +391,7 @@ xfs_attr_shortform_lookup(xfs_da_args_t *args)
continue; continue;
if (memcmp(args->name, sfe->nameval, args->namelen) != 0) if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
continue; continue;
if (((args->flags & ATTR_SECURE) != 0) != if (!xfs_attr_namesp_match(args->flags, sfe->flags))
((sfe->flags & XFS_ATTR_SECURE) != 0))
continue;
if (((args->flags & ATTR_ROOT) != 0) !=
((sfe->flags & XFS_ATTR_ROOT) != 0))
continue; continue;
return(XFS_ERROR(EEXIST)); return(XFS_ERROR(EEXIST));
} }
...@@ -394,11 +418,7 @@ xfs_attr_shortform_getvalue(xfs_da_args_t *args) ...@@ -394,11 +418,7 @@ xfs_attr_shortform_getvalue(xfs_da_args_t *args)
continue; continue;
if (memcmp(args->name, sfe->nameval, args->namelen) != 0) if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
continue; continue;
if (((args->flags & ATTR_SECURE) != 0) != if (!xfs_attr_namesp_match(args->flags, sfe->flags))
((sfe->flags & XFS_ATTR_SECURE) != 0))
continue;
if (((args->flags & ATTR_ROOT) != 0) !=
((sfe->flags & XFS_ATTR_ROOT) != 0))
continue; continue;
if (args->flags & ATTR_KERNOVAL) { if (args->flags & ATTR_KERNOVAL) {
args->valuelen = sfe->valuelen; args->valuelen = sfe->valuelen;
...@@ -485,8 +505,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args) ...@@ -485,8 +505,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
nargs.valuelen = sfe->valuelen; nargs.valuelen = sfe->valuelen;
nargs.hashval = xfs_da_hashname((char *)sfe->nameval, nargs.hashval = xfs_da_hashname((char *)sfe->nameval,
sfe->namelen); sfe->namelen);
nargs.flags = (sfe->flags & XFS_ATTR_SECURE) ? ATTR_SECURE : nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(sfe->flags);
((sfe->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);
error = xfs_attr_leaf_lookup_int(bp, &nargs); /* set a->index */ error = xfs_attr_leaf_lookup_int(bp, &nargs); /* set a->index */
ASSERT(error == ENOATTR); ASSERT(error == ENOATTR);
error = xfs_attr_leaf_add(bp, &nargs); error = xfs_attr_leaf_add(bp, &nargs);
...@@ -520,6 +539,10 @@ xfs_attr_shortform_compare(const void *a, const void *b) ...@@ -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(). * Copy out entries of shortform attribute lists for attr_list().
* Shortform attribute lists are not stored in hashval sorted order. * Shortform attribute lists are not stored in hashval sorted order.
...@@ -537,6 +560,7 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context) ...@@ -537,6 +560,7 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
xfs_attr_sf_entry_t *sfe; xfs_attr_sf_entry_t *sfe;
xfs_inode_t *dp; xfs_inode_t *dp;
int sbsize, nsbuf, count, i; int sbsize, nsbuf, count, i;
int error;
ASSERT(context != NULL); ASSERT(context != NULL);
dp = context->dp; dp = context->dp;
...@@ -552,46 +576,51 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context) ...@@ -552,46 +576,51 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
xfs_attr_trace_l_c("sf start", 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. * 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++) { for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
attrnames_t *namesp; attrnames_t *namesp;
if (((context->flags & ATTR_SECURE) != 0) != if (!xfs_attr_namesp_match_overrides(context->flags, sfe->flags)) {
((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); sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
continue; continue;
} }
namesp = (sfe->flags & XFS_ATTR_SECURE) ? &attr_secure: namesp = xfs_attr_flags_namesp(sfe->flags);
((sfe->flags & XFS_ATTR_ROOT) ? &attr_trusted : error = context->put_listent(context,
&attr_user); namesp,
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,
(char *)sfe->nameval, (char *)sfe->nameval,
(int)sfe->namelen, (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; break;
}
if (error)
return error;
sfe = XFS_ATTR_SF_NEXTENTRY(sfe); sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
} }
xfs_attr_trace_l_c("sf big-gulp", context); xfs_attr_trace_l_c("sf big-gulp", context);
return(0); 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. * 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) ...@@ -614,15 +643,7 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
kmem_free(sbuf, sbsize); kmem_free(sbuf, sbsize);
return XFS_ERROR(EFSCORRUPTED); return XFS_ERROR(EFSCORRUPTED);
} }
if (((context->flags & ATTR_SECURE) != 0) != if (!xfs_attr_namesp_match_overrides(context->flags, sfe->flags)) {
((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); sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
continue; continue;
} }
...@@ -671,24 +692,22 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context) ...@@ -671,24 +692,22 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
for ( ; i < nsbuf; i++, sbp++) { for ( ; i < nsbuf; i++, sbp++) {
attrnames_t *namesp; attrnames_t *namesp;
namesp = (sbp->flags & XFS_ATTR_SECURE) ? &attr_secure : namesp = xfs_attr_flags_namesp(sbp->flags);
((sbp->flags & XFS_ATTR_ROOT) ? &attr_trusted :
&attr_user);
if (cursor->hashval != sbp->hash) { if (cursor->hashval != sbp->hash) {
cursor->hashval = sbp->hash; cursor->hashval = sbp->hash;
cursor->offset = 0; cursor->offset = 0;
} }
if (context->flags & ATTR_KERNOVAL) { error = context->put_listent(context,
ASSERT(context->flags & ATTR_KERNAMELS); namesp,
context->count += namesp->attr_namelen + sbp->name,
sbp->namelen + 1; sbp->namelen,
} else { sbp->valuelen,
if (xfs_attr_put_listent(context, namesp, &sbp->name[sbp->namelen]);
sbp->name, sbp->namelen, if (error)
sbp->valuelen)) return error;
if (context->seen_enough)
break; break;
}
cursor->offset++; cursor->offset++;
} }
...@@ -810,8 +829,7 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff) ...@@ -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.value = (char *)&name_loc->nameval[nargs.namelen];
nargs.valuelen = be16_to_cpu(name_loc->valuelen); nargs.valuelen = be16_to_cpu(name_loc->valuelen);
nargs.hashval = be32_to_cpu(entry->hashval); nargs.hashval = be32_to_cpu(entry->hashval);
nargs.flags = (entry->flags & XFS_ATTR_SECURE) ? ATTR_SECURE : nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags);
((entry->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);
xfs_attr_shortform_add(&nargs, forkoff); xfs_attr_shortform_add(&nargs, forkoff);
} }
error = 0; error = 0;
...@@ -1098,8 +1116,7 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex) ...@@ -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)); be16_to_cpu(map->size));
entry->hashval = cpu_to_be32(args->hashval); entry->hashval = cpu_to_be32(args->hashval);
entry->flags = tmp ? XFS_ATTR_LOCAL : 0; entry->flags = tmp ? XFS_ATTR_LOCAL : 0;
entry->flags |= (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE : entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0);
if (args->rename) { if (args->rename) {
entry->flags |= XFS_ATTR_INCOMPLETE; entry->flags |= XFS_ATTR_INCOMPLETE;
if ((args->blkno2 == args->blkno) && if ((args->blkno2 == args->blkno) &&
...@@ -1971,14 +1988,9 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args) ...@@ -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); name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, probe);
if (name_loc->namelen != args->namelen) if (name_loc->namelen != args->namelen)
continue; continue;
if (memcmp(args->name, (char *)name_loc->nameval, if (memcmp(args->name, (char *)name_loc->nameval, args->namelen) != 0)
args->namelen) != 0)
continue;
if (((args->flags & ATTR_SECURE) != 0) !=
((entry->flags & XFS_ATTR_SECURE) != 0))
continue; continue;
if (((args->flags & ATTR_ROOT) != 0) != if (!xfs_attr_namesp_match(args->flags, entry->flags))
((entry->flags & XFS_ATTR_ROOT) != 0))
continue; continue;
args->index = probe; args->index = probe;
return(XFS_ERROR(EEXIST)); return(XFS_ERROR(EEXIST));
...@@ -1989,11 +2001,7 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args) ...@@ -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, if (memcmp(args->name, (char *)name_rmt->name,
args->namelen) != 0) args->namelen) != 0)
continue; continue;
if (((args->flags & ATTR_SECURE) != 0) != if (!xfs_attr_namesp_match(args->flags, entry->flags))
((entry->flags & XFS_ATTR_SECURE) != 0))
continue;
if (((args->flags & ATTR_ROOT) != 0) !=
((entry->flags & XFS_ATTR_ROOT) != 0))
continue; continue;
args->index = probe; args->index = probe;
args->rmtblkno = be32_to_cpu(name_rmt->valueblk); 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) ...@@ -2312,8 +2320,6 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
attrlist_cursor_kern_t *cursor; attrlist_cursor_kern_t *cursor;
xfs_attr_leafblock_t *leaf; xfs_attr_leafblock_t *leaf;
xfs_attr_leaf_entry_t *entry; 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; int retval, i;
ASSERT(bp != NULL); ASSERT(bp != NULL);
...@@ -2355,8 +2361,7 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context) ...@@ -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. * We have found our place, start copying out the new attributes.
*/ */
retval = 0; retval = 0;
for ( ; (i < be16_to_cpu(leaf->hdr.count)) for ( ; (i < be16_to_cpu(leaf->hdr.count)); entry++, i++) {
&& (retval == 0); entry++, i++) {
attrnames_t *namesp; attrnames_t *namesp;
if (be32_to_cpu(entry->hashval) != cursor->hashval) { 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) ...@@ -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) if (entry->flags & XFS_ATTR_INCOMPLETE)
continue; /* skip incomplete entries */ continue; /* skip incomplete entries */
if (((context->flags & ATTR_SECURE) != 0) != if (!xfs_attr_namesp_match_overrides(context->flags, entry->flags))
((entry->flags & XFS_ATTR_SECURE) != 0) && continue;
!(context->flags & ATTR_KERNORMALS))
continue; /* skip non-matching entries */ namesp = xfs_attr_flags_namesp(entry->flags);
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 (entry->flags & XFS_ATTR_LOCAL) { if (entry->flags & XFS_ATTR_LOCAL) {
name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i); xfs_attr_leaf_name_local_t *name_loc =
if (context->flags & ATTR_KERNOVAL) { XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
ASSERT(context->flags & ATTR_KERNAMELS);
context->count += namesp->attr_namelen + retval = context->put_listent(context,
(int)name_loc->namelen + 1; namesp,
} else {
retval = xfs_attr_put_listent(context, namesp,
(char *)name_loc->nameval, (char *)name_loc->nameval,
(int)name_loc->namelen, (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 { } else {
name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i); xfs_attr_leaf_name_remote_t *name_rmt =
if (context->flags & ATTR_KERNOVAL) { XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
ASSERT(context->flags & ATTR_KERNAMELS);
context->count += namesp->attr_namelen + int valuelen = be32_to_cpu(name_rmt->valuelen);
(int)name_rmt->namelen + 1;
} else { if (context->put_value) {
retval = xfs_attr_put_listent(context, namesp, 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, (char *)name_rmt->name,
(int)name_rmt->namelen, (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) { if (retval)
cursor->offset++; return retval;
} }
if (context->seen_enough)
break;
cursor->offset++;
} }
xfs_attr_trace_l_cl("blk end", context, leaf); xfs_attr_trace_l_cl("blk end", context, leaf);
return(retval); 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 * Manage the INCOMPLETE flag in a leaf entry
......
...@@ -129,6 +129,19 @@ typedef struct xfs_attr_leafblock { ...@@ -129,6 +129,19 @@ typedef struct xfs_attr_leafblock {
#define XFS_ATTR_SECURE (1 << XFS_ATTR_SECURE_BIT) #define XFS_ATTR_SECURE (1 << XFS_ATTR_SECURE_BIT)
#define XFS_ATTR_INCOMPLETE (1 << XFS_ATTR_INCOMPLETE_BIT) #define XFS_ATTR_INCOMPLETE (1 << XFS_ATTR_INCOMPLETE_BIT)
/*
* Conversion macros for converting namespace bits from argument flags
* to ondisk flags.
*/
#define XFS_ATTR_NSP_ARGS_MASK (ATTR_ROOT | ATTR_SECURE)
#define XFS_ATTR_NSP_ONDISK_MASK (XFS_ATTR_ROOT | XFS_ATTR_SECURE)
#define XFS_ATTR_NSP_ONDISK(flags) ((flags) & XFS_ATTR_NSP_ONDISK_MASK)
#define XFS_ATTR_NSP_ARGS(flags) ((flags) & XFS_ATTR_NSP_ARGS_MASK)
#define XFS_ATTR_NSP_ARGS_TO_ONDISK(x) (((x) & ATTR_ROOT ? XFS_ATTR_ROOT : 0) |\
((x) & ATTR_SECURE ? XFS_ATTR_SECURE : 0))
#define XFS_ATTR_NSP_ONDISK_TO_ARGS(x) (((x) & XFS_ATTR_ROOT ? ATTR_ROOT : 0) |\
((x) & XFS_ATTR_SECURE ? ATTR_SECURE : 0))
/* /*
* Alignment for namelist and valuelist entries (since they are mixed * Alignment for namelist and valuelist entries (since they are mixed
* there can be only one alignment value) * there can be only one alignment value)
...@@ -196,16 +209,26 @@ static inline int xfs_attr_leaf_entsize_local_max(int bsize) ...@@ -196,16 +209,26 @@ static inline int xfs_attr_leaf_entsize_local_max(int bsize)
* Structure used to pass context around among the routines. * Structure used to pass context around among the routines.
*========================================================================*/ *========================================================================*/
struct xfs_attr_list_context;
typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, struct attrnames *,
char *, int, int, char *);
typedef struct xfs_attr_list_context { typedef struct xfs_attr_list_context {
struct xfs_inode *dp; /* inode */ struct xfs_inode *dp; /* inode */
struct attrlist_cursor_kern *cursor;/* position in list */ struct attrlist_cursor_kern *cursor; /* position in list */
struct attrlist *alist; /* output buffer */ struct attrlist *alist; /* output buffer */
int seen_enough; /* T/F: seen enough of list? */
int count; /* num used entries */ int count; /* num used entries */
int dupcnt; /* count dup hashvals seen */ int dupcnt; /* count dup hashvals seen */
int bufsize;/* total buffer size */ int bufsize; /* total buffer size */
int firstu; /* first used byte in buffer */ int firstu; /* first used byte in buffer */
int flags; /* from VOP call */ int flags; /* from VOP call */
int resynch;/* T/F: resynch with cursor */ int resynch; /* T/F: resynch with cursor */
int put_value; /* T/F: need value for listent */
put_listent_func_t put_listent; /* list output fmt function */
int index; /* index into output buffer */
} xfs_attr_list_context_t; } xfs_attr_list_context_t;
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment