xfs: move the legacy xfs_attr_list to xfs_ioctl.c
The old xfs_attr_list code is only used by the attrlist by handle ioctl. Move it to xfs_ioctl.c with its user. Also move the attrlist and attrlist_ent structure to xfs_fs.h, as they are exposed user ABIs. They are used through libattr headers with the same name by at least xfsdump. Also document this relation so that it doesn't require a research project to figure out. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Chandan Rajendra <chandanrlinux@gmail.com> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
This commit is contained in:
parent
2f014aad03
commit
3e7a779937
@ -48,27 +48,6 @@ struct xfs_attr_list_context;
|
|||||||
*/
|
*/
|
||||||
#define ATTR_MAX_VALUELEN (64*1024) /* max length of a value */
|
#define ATTR_MAX_VALUELEN (64*1024) /* max length of a value */
|
||||||
|
|
||||||
/*
|
|
||||||
* Define how lists of attribute names are returned to the user from
|
|
||||||
* the attr_list() call. A large, 32bit aligned, buffer is passed in
|
|
||||||
* along with its size. We put an array of offsets at the top that each
|
|
||||||
* reference an attrlist_ent_t and pack the attrlist_ent_t's at the bottom.
|
|
||||||
*/
|
|
||||||
typedef struct attrlist {
|
|
||||||
__s32 al_count; /* number of entries in attrlist */
|
|
||||||
__s32 al_more; /* T/F: more attrs (do call again) */
|
|
||||||
__s32 al_offset[1]; /* byte offsets of attrs [var-sized] */
|
|
||||||
} attrlist_t;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Show the interesting info about one attribute. This is what the
|
|
||||||
* al_offset[i] entry points to.
|
|
||||||
*/
|
|
||||||
typedef struct attrlist_ent { /* data from attr_list() */
|
|
||||||
__u32 a_valuelen; /* number bytes in value of attr */
|
|
||||||
char a_name[1]; /* attr name (NULL terminated) */
|
|
||||||
} attrlist_ent_t;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Kernel-internal version of the attrlist cursor.
|
* Kernel-internal version of the attrlist cursor.
|
||||||
*/
|
*/
|
||||||
@ -131,8 +110,6 @@ int xfs_attr_get(struct xfs_da_args *args);
|
|||||||
int xfs_attr_set(struct xfs_da_args *args);
|
int xfs_attr_set(struct xfs_da_args *args);
|
||||||
int xfs_attr_set_args(struct xfs_da_args *args);
|
int xfs_attr_set_args(struct xfs_da_args *args);
|
||||||
int xfs_attr_remove_args(struct xfs_da_args *args);
|
int xfs_attr_remove_args(struct xfs_da_args *args);
|
||||||
int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
|
|
||||||
int flags, struct attrlist_cursor_kern *cursor);
|
|
||||||
bool xfs_attr_namecheck(const void *name, size_t length);
|
bool xfs_attr_namecheck(const void *name, size_t length);
|
||||||
|
|
||||||
#endif /* __XFS_ATTR_H__ */
|
#endif /* __XFS_ATTR_H__ */
|
||||||
|
@ -572,6 +572,26 @@ typedef struct xfs_attrlist_cursor {
|
|||||||
__u32 opaque[4];
|
__u32 opaque[4];
|
||||||
} xfs_attrlist_cursor_t;
|
} xfs_attrlist_cursor_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Define how lists of attribute names are returned to userspace from the
|
||||||
|
* XFS_IOC_ATTRLIST_BY_HANDLE ioctl. struct xfs_attrlist is the header at the
|
||||||
|
* beginning of the returned buffer, and a each entry in al_offset contains the
|
||||||
|
* relative offset of an xfs_attrlist_ent containing the actual entry.
|
||||||
|
*
|
||||||
|
* NOTE: struct xfs_attrlist must match struct attrlist defined in libattr, and
|
||||||
|
* struct xfs_attrlist_ent must match struct attrlist_ent defined in libattr.
|
||||||
|
*/
|
||||||
|
struct xfs_attrlist {
|
||||||
|
__s32 al_count; /* number of entries in attrlist */
|
||||||
|
__s32 al_more; /* T/F: more attrs (do call again) */
|
||||||
|
__s32 al_offset[1]; /* byte offsets of attrs [var-sized] */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct xfs_attrlist_ent { /* data from attr_list() */
|
||||||
|
__u32 a_valuelen; /* number bytes in value of attr */
|
||||||
|
char a_name[1]; /* attr name (NULL terminated) */
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct xfs_fsop_attrlist_handlereq {
|
typedef struct xfs_fsop_attrlist_handlereq {
|
||||||
struct xfs_fsop_handlereq hreq; /* handle interface structure */
|
struct xfs_fsop_handlereq hreq; /* handle interface structure */
|
||||||
struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */
|
struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */
|
||||||
|
@ -544,116 +544,3 @@ xfs_attr_list_int(
|
|||||||
xfs_iunlock(dp, lock_mode);
|
xfs_iunlock(dp, lock_mode);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
STATIC void
|
|
||||||
xfs_attr_put_listent(
|
|
||||||
struct xfs_attr_list_context *context,
|
|
||||||
int flags,
|
|
||||||
unsigned char *name,
|
|
||||||
int namelen,
|
|
||||||
int valuelen)
|
|
||||||
{
|
|
||||||
struct attrlist *alist = context->buffer;
|
|
||||||
struct attrlist_ent *aep;
|
|
||||||
int arraytop;
|
|
||||||
|
|
||||||
ASSERT(!context->seen_enough);
|
|
||||||
ASSERT(context->count >= 0);
|
|
||||||
ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
|
|
||||||
ASSERT(context->firstu >= sizeof(*alist));
|
|
||||||
ASSERT(context->firstu <= context->bufsize);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Only list entries in the right namespace.
|
|
||||||
*/
|
|
||||||
if (((context->flags & ATTR_SECURE) == 0) !=
|
|
||||||
((flags & XFS_ATTR_SECURE) == 0))
|
|
||||||
return;
|
|
||||||
if (((context->flags & ATTR_ROOT) == 0) !=
|
|
||||||
((flags & XFS_ATTR_ROOT) == 0))
|
|
||||||
return;
|
|
||||||
|
|
||||||
arraytop = sizeof(*alist) +
|
|
||||||
context->count * sizeof(alist->al_offset[0]);
|
|
||||||
|
|
||||||
/* decrement by the actual bytes used by the attr */
|
|
||||||
context->firstu -= round_up(offsetof(struct attrlist_ent, a_name) +
|
|
||||||
namelen + 1, sizeof(uint32_t));
|
|
||||||
if (context->firstu < arraytop) {
|
|
||||||
trace_xfs_attr_list_full(context);
|
|
||||||
alist->al_more = 1;
|
|
||||||
context->seen_enough = 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
aep = context->buffer + context->firstu;
|
|
||||||
aep->a_valuelen = valuelen;
|
|
||||||
memcpy(aep->a_name, name, namelen);
|
|
||||||
aep->a_name[namelen] = 0;
|
|
||||||
alist->al_offset[context->count++] = context->firstu;
|
|
||||||
alist->al_count = context->count;
|
|
||||||
trace_xfs_attr_list_add(context);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generate a list of extended attribute names and optionally
|
|
||||||
* also value lengths. Positive return value follows the XFS
|
|
||||||
* convention of being an error, zero or negative return code
|
|
||||||
* is the length of the buffer returned (negated), indicating
|
|
||||||
* success.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
xfs_attr_list(
|
|
||||||
struct xfs_inode *dp,
|
|
||||||
char *buffer,
|
|
||||||
int bufsize,
|
|
||||||
int flags,
|
|
||||||
struct attrlist_cursor_kern *cursor)
|
|
||||||
{
|
|
||||||
struct xfs_attr_list_context context;
|
|
||||||
struct attrlist *alist;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Validate the cursor.
|
|
||||||
*/
|
|
||||||
if (cursor->pad1 || cursor->pad2)
|
|
||||||
return -EINVAL;
|
|
||||||
if ((cursor->initted == 0) &&
|
|
||||||
(cursor->hashval || cursor->blkno || cursor->offset))
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check for a properly aligned buffer.
|
|
||||||
*/
|
|
||||||
if (((long)buffer) & (sizeof(int)-1))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize the output buffer.
|
|
||||||
*/
|
|
||||||
memset(&context, 0, sizeof(context));
|
|
||||||
context.dp = dp;
|
|
||||||
context.cursor = cursor;
|
|
||||||
context.resynch = 1;
|
|
||||||
context.flags = flags;
|
|
||||||
context.buffer = buffer;
|
|
||||||
context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */
|
|
||||||
context.firstu = context.bufsize;
|
|
||||||
context.put_listent = xfs_attr_put_listent;
|
|
||||||
|
|
||||||
alist = context.buffer;
|
|
||||||
alist->al_count = 0;
|
|
||||||
alist->al_more = 0;
|
|
||||||
alist->al_offset[0] = context.bufsize;
|
|
||||||
|
|
||||||
error = xfs_attr_list_int(&context);
|
|
||||||
ASSERT(error <= 0);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
@ -294,6 +294,111 @@ xfs_readlink_by_handle(
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
xfs_ioc_attr_put_listent(
|
||||||
|
struct xfs_attr_list_context *context,
|
||||||
|
int flags,
|
||||||
|
unsigned char *name,
|
||||||
|
int namelen,
|
||||||
|
int valuelen)
|
||||||
|
{
|
||||||
|
struct xfs_attrlist *alist = context->buffer;
|
||||||
|
struct xfs_attrlist_ent *aep;
|
||||||
|
int arraytop;
|
||||||
|
|
||||||
|
ASSERT(!context->seen_enough);
|
||||||
|
ASSERT(context->count >= 0);
|
||||||
|
ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
|
||||||
|
ASSERT(context->firstu >= sizeof(*alist));
|
||||||
|
ASSERT(context->firstu <= context->bufsize);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only list entries in the right namespace.
|
||||||
|
*/
|
||||||
|
if (((context->flags & ATTR_SECURE) == 0) !=
|
||||||
|
((flags & XFS_ATTR_SECURE) == 0))
|
||||||
|
return;
|
||||||
|
if (((context->flags & ATTR_ROOT) == 0) !=
|
||||||
|
((flags & XFS_ATTR_ROOT) == 0))
|
||||||
|
return;
|
||||||
|
|
||||||
|
arraytop = sizeof(*alist) +
|
||||||
|
context->count * sizeof(alist->al_offset[0]);
|
||||||
|
|
||||||
|
/* decrement by the actual bytes used by the attr */
|
||||||
|
context->firstu -= round_up(offsetof(struct xfs_attrlist_ent, a_name) +
|
||||||
|
namelen + 1, sizeof(uint32_t));
|
||||||
|
if (context->firstu < arraytop) {
|
||||||
|
trace_xfs_attr_list_full(context);
|
||||||
|
alist->al_more = 1;
|
||||||
|
context->seen_enough = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
aep = context->buffer + context->firstu;
|
||||||
|
aep->a_valuelen = valuelen;
|
||||||
|
memcpy(aep->a_name, name, namelen);
|
||||||
|
aep->a_name[namelen] = 0;
|
||||||
|
alist->al_offset[context->count++] = context->firstu;
|
||||||
|
alist->al_count = context->count;
|
||||||
|
trace_xfs_attr_list_add(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
xfs_ioc_attr_list(
|
||||||
|
struct xfs_inode *dp,
|
||||||
|
char *buffer,
|
||||||
|
int bufsize,
|
||||||
|
int flags,
|
||||||
|
struct attrlist_cursor_kern *cursor)
|
||||||
|
{
|
||||||
|
struct xfs_attr_list_context context;
|
||||||
|
struct xfs_attrlist *alist;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Validate the cursor.
|
||||||
|
*/
|
||||||
|
if (cursor->pad1 || cursor->pad2)
|
||||||
|
return -EINVAL;
|
||||||
|
if ((cursor->initted == 0) &&
|
||||||
|
(cursor->hashval || cursor->blkno || cursor->offset))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for a properly aligned buffer.
|
||||||
|
*/
|
||||||
|
if (((long)buffer) & (sizeof(int)-1))
|
||||||
|
return -EFAULT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the output buffer.
|
||||||
|
*/
|
||||||
|
memset(&context, 0, sizeof(context));
|
||||||
|
context.dp = dp;
|
||||||
|
context.cursor = cursor;
|
||||||
|
context.resynch = 1;
|
||||||
|
context.flags = flags;
|
||||||
|
context.buffer = buffer;
|
||||||
|
context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */
|
||||||
|
context.firstu = context.bufsize;
|
||||||
|
context.put_listent = xfs_ioc_attr_put_listent;
|
||||||
|
|
||||||
|
alist = context.buffer;
|
||||||
|
alist->al_count = 0;
|
||||||
|
alist->al_more = 0;
|
||||||
|
alist->al_offset[0] = context.bufsize;
|
||||||
|
|
||||||
|
error = xfs_attr_list_int(&context);
|
||||||
|
ASSERT(error <= 0);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
STATIC int
|
STATIC int
|
||||||
xfs_attrlist_by_handle(
|
xfs_attrlist_by_handle(
|
||||||
struct file *parfilp,
|
struct file *parfilp,
|
||||||
@ -310,7 +415,7 @@ xfs_attrlist_by_handle(
|
|||||||
return -EPERM;
|
return -EPERM;
|
||||||
if (copy_from_user(&al_hreq, arg, sizeof(xfs_fsop_attrlist_handlereq_t)))
|
if (copy_from_user(&al_hreq, arg, sizeof(xfs_fsop_attrlist_handlereq_t)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (al_hreq.buflen < sizeof(struct attrlist) ||
|
if (al_hreq.buflen < sizeof(struct xfs_attrlist) ||
|
||||||
al_hreq.buflen > XFS_XATTR_LIST_MAX)
|
al_hreq.buflen > XFS_XATTR_LIST_MAX)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -331,7 +436,7 @@ xfs_attrlist_by_handle(
|
|||||||
goto out_dput;
|
goto out_dput;
|
||||||
|
|
||||||
cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
|
cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
|
||||||
error = xfs_attr_list(XFS_I(d_inode(dentry)), kbuf, al_hreq.buflen,
|
error = xfs_ioc_attr_list(XFS_I(d_inode(dentry)), kbuf, al_hreq.buflen,
|
||||||
al_hreq.flags, cursor);
|
al_hreq.flags, cursor);
|
||||||
if (error)
|
if (error)
|
||||||
goto out_kfree;
|
goto out_kfree;
|
||||||
|
@ -6,6 +6,12 @@
|
|||||||
#ifndef __XFS_IOCTL_H__
|
#ifndef __XFS_IOCTL_H__
|
||||||
#define __XFS_IOCTL_H__
|
#define __XFS_IOCTL_H__
|
||||||
|
|
||||||
|
struct attrlist_cursor_kern;
|
||||||
|
struct xfs_bstat;
|
||||||
|
struct xfs_ibulk;
|
||||||
|
struct xfs_inogrp;
|
||||||
|
|
||||||
|
|
||||||
extern int
|
extern int
|
||||||
xfs_ioc_space(
|
xfs_ioc_space(
|
||||||
struct file *filp,
|
struct file *filp,
|
||||||
@ -33,6 +39,8 @@ xfs_readlink_by_handle(
|
|||||||
int xfs_ioc_attrmulti_one(struct file *parfilp, struct inode *inode,
|
int xfs_ioc_attrmulti_one(struct file *parfilp, struct inode *inode,
|
||||||
uint32_t opcode, void __user *uname, void __user *value,
|
uint32_t opcode, void __user *uname, void __user *value,
|
||||||
uint32_t *len, uint32_t flags);
|
uint32_t *len, uint32_t flags);
|
||||||
|
int xfs_ioc_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
|
||||||
|
int flags, struct attrlist_cursor_kern *cursor);
|
||||||
|
|
||||||
extern struct dentry *
|
extern struct dentry *
|
||||||
xfs_handle_to_dentry(
|
xfs_handle_to_dentry(
|
||||||
@ -52,10 +60,6 @@ xfs_file_compat_ioctl(
|
|||||||
unsigned int cmd,
|
unsigned int cmd,
|
||||||
unsigned long arg);
|
unsigned long arg);
|
||||||
|
|
||||||
struct xfs_ibulk;
|
|
||||||
struct xfs_bstat;
|
|
||||||
struct xfs_inogrp;
|
|
||||||
|
|
||||||
int xfs_fsbulkstat_one_fmt(struct xfs_ibulk *breq,
|
int xfs_fsbulkstat_one_fmt(struct xfs_ibulk *breq,
|
||||||
const struct xfs_bulkstat *bstat);
|
const struct xfs_bulkstat *bstat);
|
||||||
int xfs_fsinumbers_fmt(struct xfs_ibulk *breq, const struct xfs_inumbers *igrp);
|
int xfs_fsinumbers_fmt(struct xfs_ibulk *breq, const struct xfs_inumbers *igrp);
|
||||||
|
@ -366,7 +366,7 @@ xfs_compat_attrlist_by_handle(
|
|||||||
if (copy_from_user(&al_hreq, arg,
|
if (copy_from_user(&al_hreq, arg,
|
||||||
sizeof(compat_xfs_fsop_attrlist_handlereq_t)))
|
sizeof(compat_xfs_fsop_attrlist_handlereq_t)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (al_hreq.buflen < sizeof(struct attrlist) ||
|
if (al_hreq.buflen < sizeof(struct xfs_attrlist) ||
|
||||||
al_hreq.buflen > XFS_XATTR_LIST_MAX)
|
al_hreq.buflen > XFS_XATTR_LIST_MAX)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -388,7 +388,7 @@ xfs_compat_attrlist_by_handle(
|
|||||||
goto out_dput;
|
goto out_dput;
|
||||||
|
|
||||||
cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
|
cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;
|
||||||
error = xfs_attr_list(XFS_I(d_inode(dentry)), kbuf, al_hreq.buflen,
|
error = xfs_ioc_attr_list(XFS_I(d_inode(dentry)), kbuf, al_hreq.buflen,
|
||||||
al_hreq.flags, cursor);
|
al_hreq.flags, cursor);
|
||||||
if (error)
|
if (error)
|
||||||
goto out_kfree;
|
goto out_kfree;
|
||||||
|
Loading…
Reference in New Issue
Block a user