|
@@ -16,8 +16,6 @@
|
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
*/
|
|
|
|
|
|
-#include <linux/capability.h>
|
|
|
-
|
|
|
#include "xfs.h"
|
|
|
#include "xfs_fs.h"
|
|
|
#include "xfs_types.h"
|
|
@@ -57,11 +55,6 @@
|
|
|
* Provide the external interfaces to manage attribute lists.
|
|
|
*/
|
|
|
|
|
|
-#define ATTR_SYSCOUNT 2
|
|
|
-static struct attrnames posix_acl_access;
|
|
|
-static struct attrnames posix_acl_default;
|
|
|
-static struct attrnames *attr_system_names[ATTR_SYSCOUNT];
|
|
|
-
|
|
|
/*========================================================================
|
|
|
* Function prototypes for the kernel.
|
|
|
*========================================================================*/
|
|
@@ -116,6 +109,17 @@ xfs_attr_name_to_xname(
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+STATIC int
|
|
|
+xfs_inode_hasattr(
|
|
|
+ struct xfs_inode *ip)
|
|
|
+{
|
|
|
+ if (!XFS_IFORK_Q(ip) ||
|
|
|
+ (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
|
|
|
+ ip->i_d.di_anextents == 0))
|
|
|
+ return 0;
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
/*========================================================================
|
|
|
* Overall external interface routines.
|
|
|
*========================================================================*/
|
|
@@ -127,10 +131,8 @@ xfs_attr_fetch(xfs_inode_t *ip, struct xfs_name *name,
|
|
|
xfs_da_args_t args;
|
|
|
int error;
|
|
|
|
|
|
- if ((XFS_IFORK_Q(ip) == 0) ||
|
|
|
- (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
|
|
|
- ip->i_d.di_anextents == 0))
|
|
|
- return(ENOATTR);
|
|
|
+ if (!xfs_inode_hasattr(ip))
|
|
|
+ return ENOATTR;
|
|
|
|
|
|
/*
|
|
|
* Fill in the arg structure for this request.
|
|
@@ -148,11 +150,7 @@ xfs_attr_fetch(xfs_inode_t *ip, struct xfs_name *name,
|
|
|
/*
|
|
|
* Decide on what work routines to call based on the inode size.
|
|
|
*/
|
|
|
- if (XFS_IFORK_Q(ip) == 0 ||
|
|
|
- (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
|
|
|
- ip->i_d.di_anextents == 0)) {
|
|
|
- error = XFS_ERROR(ENOATTR);
|
|
|
- } else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
|
|
|
+ if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
|
|
|
error = xfs_attr_shortform_getvalue(&args);
|
|
|
} else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) {
|
|
|
error = xfs_attr_leaf_get(&args);
|
|
@@ -241,8 +239,7 @@ xfs_attr_set_int(xfs_inode_t *dp, struct xfs_name *name,
|
|
|
args.firstblock = &firstblock;
|
|
|
args.flist = &flist;
|
|
|
args.whichfork = XFS_ATTR_FORK;
|
|
|
- args.addname = 1;
|
|
|
- args.oknoent = 1;
|
|
|
+ args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
|
|
|
|
|
|
/*
|
|
|
* Determine space new attribute will use, and if it would be
|
|
@@ -529,9 +526,7 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
|
|
|
/*
|
|
|
* 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)) {
|
|
|
+ if (!xfs_inode_hasattr(dp)) {
|
|
|
error = XFS_ERROR(ENOATTR);
|
|
|
goto out;
|
|
|
}
|
|
@@ -601,29 +596,33 @@ xfs_attr_remove(
|
|
|
return error;
|
|
|
|
|
|
xfs_ilock(dp, XFS_ILOCK_SHARED);
|
|
|
- if (XFS_IFORK_Q(dp) == 0 ||
|
|
|
- (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
|
|
|
- dp->i_d.di_anextents == 0)) {
|
|
|
+ if (!xfs_inode_hasattr(dp)) {
|
|
|
xfs_iunlock(dp, XFS_ILOCK_SHARED);
|
|
|
- return(XFS_ERROR(ENOATTR));
|
|
|
+ return XFS_ERROR(ENOATTR);
|
|
|
}
|
|
|
xfs_iunlock(dp, XFS_ILOCK_SHARED);
|
|
|
|
|
|
return xfs_attr_remove_int(dp, &xname, flags);
|
|
|
}
|
|
|
|
|
|
-STATIC int
|
|
|
+int
|
|
|
xfs_attr_list_int(xfs_attr_list_context_t *context)
|
|
|
{
|
|
|
int error;
|
|
|
xfs_inode_t *dp = context->dp;
|
|
|
|
|
|
+ XFS_STATS_INC(xs_attr_list);
|
|
|
+
|
|
|
+ if (XFS_FORCED_SHUTDOWN(dp->i_mount))
|
|
|
+ return EIO;
|
|
|
+
|
|
|
+ xfs_ilock(dp, XFS_ILOCK_SHARED);
|
|
|
+ xfs_attr_trace_l_c("syscall start", context);
|
|
|
+
|
|
|
/*
|
|
|
* 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)) {
|
|
|
+ if (!xfs_inode_hasattr(dp)) {
|
|
|
error = 0;
|
|
|
} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
|
|
|
error = xfs_attr_shortform_list(context);
|
|
@@ -632,6 +631,10 @@ xfs_attr_list_int(xfs_attr_list_context_t *context)
|
|
|
} else {
|
|
|
error = xfs_attr_node_list(context);
|
|
|
}
|
|
|
+
|
|
|
+ xfs_iunlock(dp, XFS_ILOCK_SHARED);
|
|
|
+ xfs_attr_trace_l_c("syscall end", context);
|
|
|
+
|
|
|
return error;
|
|
|
}
|
|
|
|
|
@@ -648,74 +651,50 @@ xfs_attr_list_int(xfs_attr_list_context_t *context)
|
|
|
*/
|
|
|
/*ARGSUSED*/
|
|
|
STATIC int
|
|
|
-xfs_attr_put_listent(xfs_attr_list_context_t *context, attrnames_t *namesp,
|
|
|
+xfs_attr_put_listent(xfs_attr_list_context_t *context, int flags,
|
|
|
char *name, int namelen,
|
|
|
int valuelen, char *value)
|
|
|
{
|
|
|
+ struct attrlist *alist = (struct attrlist *)context->alist;
|
|
|
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 >= sizeof(*alist));
|
|
|
ASSERT(context->firstu <= context->bufsize);
|
|
|
|
|
|
- arraytop = sizeof(*context->alist) +
|
|
|
- context->count * sizeof(context->alist->al_offset[0]);
|
|
|
+ /*
|
|
|
+ * Only list entries in the right namespace.
|
|
|
+ */
|
|
|
+ if (((context->flags & ATTR_SECURE) == 0) !=
|
|
|
+ ((flags & XFS_ATTR_SECURE) == 0))
|
|
|
+ return 0;
|
|
|
+ if (((context->flags & ATTR_ROOT) == 0) !=
|
|
|
+ ((flags & XFS_ATTR_ROOT) == 0))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ arraytop = sizeof(*alist) +
|
|
|
+ context->count * sizeof(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;
|
|
|
+ alist->al_more = 1;
|
|
|
context->seen_enough = 1;
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
- aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]);
|
|
|
+ aep = (attrlist_ent_t *)&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;
|
|
|
+ aep->a_name[namelen] = 0;
|
|
|
+ alist->al_offset[context->count++] = context->firstu;
|
|
|
+ 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
|
|
@@ -732,10 +711,9 @@ xfs_attr_list(
|
|
|
attrlist_cursor_kern_t *cursor)
|
|
|
{
|
|
|
xfs_attr_list_context_t context;
|
|
|
+ struct attrlist *alist;
|
|
|
int error;
|
|
|
|
|
|
- XFS_STATS_INC(xs_attr_list);
|
|
|
-
|
|
|
/*
|
|
|
* Validate the cursor.
|
|
|
*/
|
|
@@ -756,52 +734,23 @@ xfs_attr_list(
|
|
|
/*
|
|
|
* Initialize the output buffer.
|
|
|
*/
|
|
|
+ memset(&context, 0, sizeof(context));
|
|
|
context.dp = dp;
|
|
|
context.cursor = cursor;
|
|
|
- context.count = 0;
|
|
|
- context.dupcnt = 0;
|
|
|
context.resynch = 1;
|
|
|
context.flags = flags;
|
|
|
- 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->al_count = 0;
|
|
|
- context.alist->al_more = 0;
|
|
|
- context.alist->al_offset[0] = context.bufsize;
|
|
|
- context.put_listent = xfs_attr_put_listent;
|
|
|
- }
|
|
|
+ context.alist = buffer;
|
|
|
+ context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */
|
|
|
+ context.firstu = context.bufsize;
|
|
|
+ context.put_listent = xfs_attr_put_listent;
|
|
|
|
|
|
- if (XFS_FORCED_SHUTDOWN(dp->i_mount))
|
|
|
- return EIO;
|
|
|
-
|
|
|
- xfs_ilock(dp, XFS_ILOCK_SHARED);
|
|
|
- xfs_attr_trace_l_c("syscall start", &context);
|
|
|
+ alist = (struct attrlist *)context.alist;
|
|
|
+ alist->al_count = 0;
|
|
|
+ alist->al_more = 0;
|
|
|
+ alist->al_offset[0] = context.bufsize;
|
|
|
|
|
|
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)) {
|
|
|
- /* must return negated buffer size or the error */
|
|
|
- if (context.count < 0)
|
|
|
- error = XFS_ERROR(ERANGE);
|
|
|
- else
|
|
|
- error = -context.count;
|
|
|
- } else
|
|
|
- ASSERT(error >= 0);
|
|
|
-
|
|
|
+ ASSERT(error >= 0);
|
|
|
return error;
|
|
|
}
|
|
|
|
|
@@ -816,12 +765,10 @@ xfs_attr_inactive(xfs_inode_t *dp)
|
|
|
ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
|
|
|
|
|
|
xfs_ilock(dp, XFS_ILOCK_SHARED);
|
|
|
- if ((XFS_IFORK_Q(dp) == 0) ||
|
|
|
- (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
|
|
|
- (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
|
|
|
- dp->i_d.di_anextents == 0)) {
|
|
|
+ if (!xfs_inode_hasattr(dp) ||
|
|
|
+ dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
|
|
|
xfs_iunlock(dp, XFS_ILOCK_SHARED);
|
|
|
- return(0);
|
|
|
+ return 0;
|
|
|
}
|
|
|
xfs_iunlock(dp, XFS_ILOCK_SHARED);
|
|
|
|
|
@@ -854,10 +801,8 @@ xfs_attr_inactive(xfs_inode_t *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_LOCAL) ||
|
|
|
- (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
|
|
|
- dp->i_d.di_anextents == 0)) {
|
|
|
+ if (!xfs_inode_hasattr(dp) ||
|
|
|
+ dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
|
|
|
error = 0;
|
|
|
goto out;
|
|
|
}
|
|
@@ -974,7 +919,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
|
|
|
xfs_da_brelse(args->trans, bp);
|
|
|
return(retval);
|
|
|
}
|
|
|
- args->rename = 1; /* an atomic rename */
|
|
|
+ args->op_flags |= XFS_DA_OP_RENAME; /* an atomic rename */
|
|
|
args->blkno2 = args->blkno; /* set 2nd entry info*/
|
|
|
args->index2 = args->index;
|
|
|
args->rmtblkno2 = args->rmtblkno;
|
|
@@ -1054,7 +999,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args)
|
|
|
* so that one disappears and one appears atomically. Then we
|
|
|
* must remove the "old" attribute/value pair.
|
|
|
*/
|
|
|
- if (args->rename) {
|
|
|
+ if (args->op_flags & XFS_DA_OP_RENAME) {
|
|
|
/*
|
|
|
* In a separate transaction, set the incomplete flag on the
|
|
|
* "old" attr and clear the incomplete flag on the "new" attr.
|
|
@@ -1307,7 +1252,7 @@ restart:
|
|
|
} else if (retval == EEXIST) {
|
|
|
if (args->flags & ATTR_CREATE)
|
|
|
goto out;
|
|
|
- args->rename = 1; /* atomic rename op */
|
|
|
+ args->op_flags |= XFS_DA_OP_RENAME; /* atomic rename op */
|
|
|
args->blkno2 = args->blkno; /* set 2nd entry info*/
|
|
|
args->index2 = args->index;
|
|
|
args->rmtblkno2 = args->rmtblkno;
|
|
@@ -1425,7 +1370,7 @@ restart:
|
|
|
* so that one disappears and one appears atomically. Then we
|
|
|
* must remove the "old" attribute/value pair.
|
|
|
*/
|
|
|
- if (args->rename) {
|
|
|
+ if (args->op_flags & XFS_DA_OP_RENAME) {
|
|
|
/*
|
|
|
* In a separate transaction, set the incomplete flag on the
|
|
|
* "old" attr and clear the incomplete flag on the "new" attr.
|
|
@@ -2300,23 +2245,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args)
|
|
|
void
|
|
|
xfs_attr_trace_l_c(char *where, struct xfs_attr_list_context *context)
|
|
|
{
|
|
|
- xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where,
|
|
|
- (__psunsigned_t)context->dp,
|
|
|
- (__psunsigned_t)context->cursor->hashval,
|
|
|
- (__psunsigned_t)context->cursor->blkno,
|
|
|
- (__psunsigned_t)context->cursor->offset,
|
|
|
- (__psunsigned_t)context->alist,
|
|
|
- (__psunsigned_t)context->bufsize,
|
|
|
- (__psunsigned_t)context->count,
|
|
|
- (__psunsigned_t)context->firstu,
|
|
|
- (__psunsigned_t)
|
|
|
- ((context->count > 0) &&
|
|
|
- !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
|
|
|
- ? (ATTR_ENTRY(context->alist,
|
|
|
- context->count-1)->a_valuelen)
|
|
|
- : 0,
|
|
|
- (__psunsigned_t)context->dupcnt,
|
|
|
- (__psunsigned_t)context->flags,
|
|
|
+ xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_C, where, context,
|
|
|
(__psunsigned_t)NULL,
|
|
|
(__psunsigned_t)NULL,
|
|
|
(__psunsigned_t)NULL);
|
|
@@ -2329,23 +2258,7 @@ void
|
|
|
xfs_attr_trace_l_cn(char *where, struct xfs_attr_list_context *context,
|
|
|
struct xfs_da_intnode *node)
|
|
|
{
|
|
|
- xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where,
|
|
|
- (__psunsigned_t)context->dp,
|
|
|
- (__psunsigned_t)context->cursor->hashval,
|
|
|
- (__psunsigned_t)context->cursor->blkno,
|
|
|
- (__psunsigned_t)context->cursor->offset,
|
|
|
- (__psunsigned_t)context->alist,
|
|
|
- (__psunsigned_t)context->bufsize,
|
|
|
- (__psunsigned_t)context->count,
|
|
|
- (__psunsigned_t)context->firstu,
|
|
|
- (__psunsigned_t)
|
|
|
- ((context->count > 0) &&
|
|
|
- !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
|
|
|
- ? (ATTR_ENTRY(context->alist,
|
|
|
- context->count-1)->a_valuelen)
|
|
|
- : 0,
|
|
|
- (__psunsigned_t)context->dupcnt,
|
|
|
- (__psunsigned_t)context->flags,
|
|
|
+ xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CN, where, context,
|
|
|
(__psunsigned_t)be16_to_cpu(node->hdr.count),
|
|
|
(__psunsigned_t)be32_to_cpu(node->btree[0].hashval),
|
|
|
(__psunsigned_t)be32_to_cpu(node->btree[
|
|
@@ -2359,23 +2272,7 @@ void
|
|
|
xfs_attr_trace_l_cb(char *where, struct xfs_attr_list_context *context,
|
|
|
struct xfs_da_node_entry *btree)
|
|
|
{
|
|
|
- xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where,
|
|
|
- (__psunsigned_t)context->dp,
|
|
|
- (__psunsigned_t)context->cursor->hashval,
|
|
|
- (__psunsigned_t)context->cursor->blkno,
|
|
|
- (__psunsigned_t)context->cursor->offset,
|
|
|
- (__psunsigned_t)context->alist,
|
|
|
- (__psunsigned_t)context->bufsize,
|
|
|
- (__psunsigned_t)context->count,
|
|
|
- (__psunsigned_t)context->firstu,
|
|
|
- (__psunsigned_t)
|
|
|
- ((context->count > 0) &&
|
|
|
- !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
|
|
|
- ? (ATTR_ENTRY(context->alist,
|
|
|
- context->count-1)->a_valuelen)
|
|
|
- : 0,
|
|
|
- (__psunsigned_t)context->dupcnt,
|
|
|
- (__psunsigned_t)context->flags,
|
|
|
+ xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CB, where, context,
|
|
|
(__psunsigned_t)be32_to_cpu(btree->hashval),
|
|
|
(__psunsigned_t)be32_to_cpu(btree->before),
|
|
|
(__psunsigned_t)NULL);
|
|
@@ -2388,23 +2285,7 @@ void
|
|
|
xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context,
|
|
|
struct xfs_attr_leafblock *leaf)
|
|
|
{
|
|
|
- xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where,
|
|
|
- (__psunsigned_t)context->dp,
|
|
|
- (__psunsigned_t)context->cursor->hashval,
|
|
|
- (__psunsigned_t)context->cursor->blkno,
|
|
|
- (__psunsigned_t)context->cursor->offset,
|
|
|
- (__psunsigned_t)context->alist,
|
|
|
- (__psunsigned_t)context->bufsize,
|
|
|
- (__psunsigned_t)context->count,
|
|
|
- (__psunsigned_t)context->firstu,
|
|
|
- (__psunsigned_t)
|
|
|
- ((context->count > 0) &&
|
|
|
- !(context->flags & (ATTR_KERNAMELS|ATTR_KERNOVAL)))
|
|
|
- ? (ATTR_ENTRY(context->alist,
|
|
|
- context->count-1)->a_valuelen)
|
|
|
- : 0,
|
|
|
- (__psunsigned_t)context->dupcnt,
|
|
|
- (__psunsigned_t)context->flags,
|
|
|
+ xfs_attr_trace_enter(XFS_ATTR_KTRACE_L_CL, where, context,
|
|
|
(__psunsigned_t)be16_to_cpu(leaf->hdr.count),
|
|
|
(__psunsigned_t)be32_to_cpu(leaf->entries[0].hashval),
|
|
|
(__psunsigned_t)be32_to_cpu(leaf->entries[
|
|
@@ -2417,329 +2298,24 @@ xfs_attr_trace_l_cl(char *where, struct xfs_attr_list_context *context,
|
|
|
*/
|
|
|
void
|
|
|
xfs_attr_trace_enter(int type, char *where,
|
|
|
- __psunsigned_t a2, __psunsigned_t a3,
|
|
|
- __psunsigned_t a4, __psunsigned_t a5,
|
|
|
- __psunsigned_t a6, __psunsigned_t a7,
|
|
|
- __psunsigned_t a8, __psunsigned_t a9,
|
|
|
- __psunsigned_t a10, __psunsigned_t a11,
|
|
|
- __psunsigned_t a12, __psunsigned_t a13,
|
|
|
- __psunsigned_t a14, __psunsigned_t a15)
|
|
|
+ struct xfs_attr_list_context *context,
|
|
|
+ __psunsigned_t a13, __psunsigned_t a14,
|
|
|
+ __psunsigned_t a15)
|
|
|
{
|
|
|
ASSERT(xfs_attr_trace_buf);
|
|
|
ktrace_enter(xfs_attr_trace_buf, (void *)((__psunsigned_t)type),
|
|
|
- (void *)where,
|
|
|
- (void *)a2, (void *)a3, (void *)a4,
|
|
|
- (void *)a5, (void *)a6, (void *)a7,
|
|
|
- (void *)a8, (void *)a9, (void *)a10,
|
|
|
- (void *)a11, (void *)a12, (void *)a13,
|
|
|
- (void *)a14, (void *)a15);
|
|
|
+ (void *)((__psunsigned_t)where),
|
|
|
+ (void *)((__psunsigned_t)context->dp),
|
|
|
+ (void *)((__psunsigned_t)context->cursor->hashval),
|
|
|
+ (void *)((__psunsigned_t)context->cursor->blkno),
|
|
|
+ (void *)((__psunsigned_t)context->cursor->offset),
|
|
|
+ (void *)((__psunsigned_t)context->alist),
|
|
|
+ (void *)((__psunsigned_t)context->bufsize),
|
|
|
+ (void *)((__psunsigned_t)context->count),
|
|
|
+ (void *)((__psunsigned_t)context->firstu),
|
|
|
+ NULL,
|
|
|
+ (void *)((__psunsigned_t)context->dupcnt),
|
|
|
+ (void *)((__psunsigned_t)context->flags),
|
|
|
+ (void *)a13, (void *)a14, (void *)a15);
|
|
|
}
|
|
|
#endif /* XFS_ATTR_TRACE */
|
|
|
-
|
|
|
-
|
|
|
-/*========================================================================
|
|
|
- * System (pseudo) namespace attribute interface routines.
|
|
|
- *========================================================================*/
|
|
|
-
|
|
|
-STATIC int
|
|
|
-posix_acl_access_set(
|
|
|
- bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
|
|
|
-{
|
|
|
- return xfs_acl_vset(vp, data, size, _ACL_TYPE_ACCESS);
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-posix_acl_access_remove(
|
|
|
- bhv_vnode_t *vp, char *name, int xflags)
|
|
|
-{
|
|
|
- return xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-posix_acl_access_get(
|
|
|
- bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
|
|
|
-{
|
|
|
- return xfs_acl_vget(vp, data, size, _ACL_TYPE_ACCESS);
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-posix_acl_access_exists(
|
|
|
- bhv_vnode_t *vp)
|
|
|
-{
|
|
|
- return xfs_acl_vhasacl_access(vp);
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-posix_acl_default_set(
|
|
|
- bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
|
|
|
-{
|
|
|
- return xfs_acl_vset(vp, data, size, _ACL_TYPE_DEFAULT);
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-posix_acl_default_get(
|
|
|
- bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
|
|
|
-{
|
|
|
- return xfs_acl_vget(vp, data, size, _ACL_TYPE_DEFAULT);
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-posix_acl_default_remove(
|
|
|
- bhv_vnode_t *vp, char *name, int xflags)
|
|
|
-{
|
|
|
- return xfs_acl_vremove(vp, _ACL_TYPE_DEFAULT);
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-posix_acl_default_exists(
|
|
|
- bhv_vnode_t *vp)
|
|
|
-{
|
|
|
- return xfs_acl_vhasacl_default(vp);
|
|
|
-}
|
|
|
-
|
|
|
-static struct attrnames posix_acl_access = {
|
|
|
- .attr_name = "posix_acl_access",
|
|
|
- .attr_namelen = sizeof("posix_acl_access") - 1,
|
|
|
- .attr_get = posix_acl_access_get,
|
|
|
- .attr_set = posix_acl_access_set,
|
|
|
- .attr_remove = posix_acl_access_remove,
|
|
|
- .attr_exists = posix_acl_access_exists,
|
|
|
-};
|
|
|
-
|
|
|
-static struct attrnames posix_acl_default = {
|
|
|
- .attr_name = "posix_acl_default",
|
|
|
- .attr_namelen = sizeof("posix_acl_default") - 1,
|
|
|
- .attr_get = posix_acl_default_get,
|
|
|
- .attr_set = posix_acl_default_set,
|
|
|
- .attr_remove = posix_acl_default_remove,
|
|
|
- .attr_exists = posix_acl_default_exists,
|
|
|
-};
|
|
|
-
|
|
|
-static struct attrnames *attr_system_names[] =
|
|
|
- { &posix_acl_access, &posix_acl_default };
|
|
|
-
|
|
|
-
|
|
|
-/*========================================================================
|
|
|
- * Namespace-prefix-style attribute name interface routines.
|
|
|
- *========================================================================*/
|
|
|
-
|
|
|
-STATIC int
|
|
|
-attr_generic_set(
|
|
|
- bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
|
|
|
-{
|
|
|
- return -xfs_attr_set(xfs_vtoi(vp), name, data, size, xflags);
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-attr_generic_get(
|
|
|
- bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
|
|
|
-{
|
|
|
- int error, asize = size;
|
|
|
-
|
|
|
- error = xfs_attr_get(xfs_vtoi(vp), name, data, &asize, xflags);
|
|
|
- if (!error)
|
|
|
- return asize;
|
|
|
- return -error;
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-attr_generic_remove(
|
|
|
- bhv_vnode_t *vp, char *name, int xflags)
|
|
|
-{
|
|
|
- return -xfs_attr_remove(xfs_vtoi(vp), name, xflags);
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-attr_generic_listadd(
|
|
|
- attrnames_t *prefix,
|
|
|
- attrnames_t *namesp,
|
|
|
- void *data,
|
|
|
- size_t size,
|
|
|
- ssize_t *result)
|
|
|
-{
|
|
|
- char *p = data + *result;
|
|
|
-
|
|
|
- *result += prefix->attr_namelen;
|
|
|
- *result += namesp->attr_namelen + 1;
|
|
|
- if (!size)
|
|
|
- return 0;
|
|
|
- if (*result > size)
|
|
|
- return -ERANGE;
|
|
|
- strcpy(p, prefix->attr_name);
|
|
|
- p += prefix->attr_namelen;
|
|
|
- strcpy(p, namesp->attr_name);
|
|
|
- p += namesp->attr_namelen + 1;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-attr_system_list(
|
|
|
- bhv_vnode_t *vp,
|
|
|
- void *data,
|
|
|
- size_t size,
|
|
|
- ssize_t *result)
|
|
|
-{
|
|
|
- attrnames_t *namesp;
|
|
|
- int i, error = 0;
|
|
|
-
|
|
|
- for (i = 0; i < ATTR_SYSCOUNT; i++) {
|
|
|
- namesp = attr_system_names[i];
|
|
|
- if (!namesp->attr_exists || !namesp->attr_exists(vp))
|
|
|
- continue;
|
|
|
- error = attr_generic_listadd(&attr_system, namesp,
|
|
|
- data, size, result);
|
|
|
- if (error)
|
|
|
- break;
|
|
|
- }
|
|
|
- return error;
|
|
|
-}
|
|
|
-
|
|
|
-int
|
|
|
-attr_generic_list(
|
|
|
- bhv_vnode_t *vp, void *data, size_t size, int xflags, ssize_t *result)
|
|
|
-{
|
|
|
- attrlist_cursor_kern_t cursor = { 0 };
|
|
|
- int error;
|
|
|
-
|
|
|
- error = xfs_attr_list(xfs_vtoi(vp), data, size, xflags, &cursor);
|
|
|
- if (error > 0)
|
|
|
- return -error;
|
|
|
- *result = -error;
|
|
|
- return attr_system_list(vp, data, size, result);
|
|
|
-}
|
|
|
-
|
|
|
-attrnames_t *
|
|
|
-attr_lookup_namespace(
|
|
|
- char *name,
|
|
|
- struct attrnames **names,
|
|
|
- int nnames)
|
|
|
-{
|
|
|
- int i;
|
|
|
-
|
|
|
- for (i = 0; i < nnames; i++)
|
|
|
- if (!strncmp(name, names[i]->attr_name, names[i]->attr_namelen))
|
|
|
- return names[i];
|
|
|
- return NULL;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Some checks to prevent people abusing EAs to get over quota:
|
|
|
- * - Don't allow modifying user EAs on devices/symlinks;
|
|
|
- * - Don't allow modifying user EAs if sticky bit set;
|
|
|
- */
|
|
|
-STATIC int
|
|
|
-attr_user_capable(
|
|
|
- bhv_vnode_t *vp,
|
|
|
- cred_t *cred)
|
|
|
-{
|
|
|
- struct inode *inode = vn_to_inode(vp);
|
|
|
-
|
|
|
- if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
|
|
|
- return -EPERM;
|
|
|
- if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) &&
|
|
|
- !capable(CAP_SYS_ADMIN))
|
|
|
- return -EPERM;
|
|
|
- if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) &&
|
|
|
- (current_fsuid(cred) != inode->i_uid) && !capable(CAP_FOWNER))
|
|
|
- return -EPERM;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-attr_trusted_capable(
|
|
|
- bhv_vnode_t *vp,
|
|
|
- cred_t *cred)
|
|
|
-{
|
|
|
- struct inode *inode = vn_to_inode(vp);
|
|
|
-
|
|
|
- if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
|
|
|
- return -EPERM;
|
|
|
- if (!capable(CAP_SYS_ADMIN))
|
|
|
- return -EPERM;
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-attr_system_set(
|
|
|
- bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
|
|
|
-{
|
|
|
- attrnames_t *namesp;
|
|
|
- int error;
|
|
|
-
|
|
|
- if (xflags & ATTR_CREATE)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
|
|
|
- if (!namesp)
|
|
|
- return -EOPNOTSUPP;
|
|
|
- error = namesp->attr_set(vp, name, data, size, xflags);
|
|
|
- if (!error)
|
|
|
- error = vn_revalidate(vp);
|
|
|
- return error;
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-attr_system_get(
|
|
|
- bhv_vnode_t *vp, char *name, void *data, size_t size, int xflags)
|
|
|
-{
|
|
|
- attrnames_t *namesp;
|
|
|
-
|
|
|
- namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
|
|
|
- if (!namesp)
|
|
|
- return -EOPNOTSUPP;
|
|
|
- return namesp->attr_get(vp, name, data, size, xflags);
|
|
|
-}
|
|
|
-
|
|
|
-STATIC int
|
|
|
-attr_system_remove(
|
|
|
- bhv_vnode_t *vp, char *name, int xflags)
|
|
|
-{
|
|
|
- attrnames_t *namesp;
|
|
|
-
|
|
|
- namesp = attr_lookup_namespace(name, attr_system_names, ATTR_SYSCOUNT);
|
|
|
- if (!namesp)
|
|
|
- return -EOPNOTSUPP;
|
|
|
- return namesp->attr_remove(vp, name, xflags);
|
|
|
-}
|
|
|
-
|
|
|
-struct attrnames attr_system = {
|
|
|
- .attr_name = "system.",
|
|
|
- .attr_namelen = sizeof("system.") - 1,
|
|
|
- .attr_flag = ATTR_SYSTEM,
|
|
|
- .attr_get = attr_system_get,
|
|
|
- .attr_set = attr_system_set,
|
|
|
- .attr_remove = attr_system_remove,
|
|
|
- .attr_capable = (attrcapable_t)fs_noerr,
|
|
|
-};
|
|
|
-
|
|
|
-struct attrnames attr_trusted = {
|
|
|
- .attr_name = "trusted.",
|
|
|
- .attr_namelen = sizeof("trusted.") - 1,
|
|
|
- .attr_flag = ATTR_ROOT,
|
|
|
- .attr_get = attr_generic_get,
|
|
|
- .attr_set = attr_generic_set,
|
|
|
- .attr_remove = attr_generic_remove,
|
|
|
- .attr_capable = attr_trusted_capable,
|
|
|
-};
|
|
|
-
|
|
|
-struct attrnames attr_secure = {
|
|
|
- .attr_name = "security.",
|
|
|
- .attr_namelen = sizeof("security.") - 1,
|
|
|
- .attr_flag = ATTR_SECURE,
|
|
|
- .attr_get = attr_generic_get,
|
|
|
- .attr_set = attr_generic_set,
|
|
|
- .attr_remove = attr_generic_remove,
|
|
|
- .attr_capable = (attrcapable_t)fs_noerr,
|
|
|
-};
|
|
|
-
|
|
|
-struct attrnames attr_user = {
|
|
|
- .attr_name = "user.",
|
|
|
- .attr_namelen = sizeof("user.") - 1,
|
|
|
- .attr_get = attr_generic_get,
|
|
|
- .attr_set = attr_generic_set,
|
|
|
- .attr_remove = attr_generic_remove,
|
|
|
- .attr_capable = attr_user_capable,
|
|
|
-};
|
|
|
-
|
|
|
-struct attrnames *attr_namespaces[] =
|
|
|
- { &attr_system, &attr_trusted, &attr_secure, &attr_user };
|