Commit 28750975 authored by sandeen@sandeen.net's avatar sandeen@sandeen.net Committed by Lachlan McIlroy
Browse files

[XFS] Hook up compat XFS_IOC_ATTRMULTI_BY_HANDLE ioctl handler



Add a compat handler for XFS_IOC_ATTRMULTI_BY_HANDLE

Signed-off-by: default avatarEric Sandeen <sandeen@sandeen.net>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarLachlan McIlroy <lachlan@sgi.com>
parent ebeecd2b
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -490,7 +490,7 @@ xfs_attrlist_by_handle(
	return -error;
}

STATIC int
int
xfs_attrmulti_attr_get(
	struct inode		*inode,
	char			*name,
@@ -519,7 +519,7 @@ xfs_attrmulti_attr_get(
	return error;
}

STATIC int
int
xfs_attrmulti_attr_set(
	struct inode		*inode,
	char			*name,
@@ -549,7 +549,7 @@ xfs_attrmulti_attr_set(
	return error;
}

STATIC int
int
xfs_attrmulti_attr_remove(
	struct inode		*inode,
	char			*name,
+23 −0
Original line number Diff line number Diff line
@@ -44,4 +44,27 @@ xfs_readlink_by_handle(
	xfs_mount_t		*mp,
	xfs_fsop_handlereq_t	*hreq,
	struct inode		*parinode);

extern int
xfs_attrmulti_attr_get(
	struct inode		*inode,
	char			*name,
	char			__user *ubuf,
	__uint32_t		*len,
	__uint32_t		flags);

extern int
	xfs_attrmulti_attr_set(
	struct inode		*inode,
	char			*name,
	const char		__user *ubuf,
	__uint32_t		len,
	__uint32_t		flags);

extern int
xfs_attrmulti_attr_remove(
	struct inode		*inode,
	char			*name,
	__uint32_t		flags);

#endif
+90 −4
Original line number Diff line number Diff line
@@ -476,6 +476,93 @@ xfs_compat_attrlist_by_handle(
	return -error;
}

STATIC int
xfs_compat_attrmulti_by_handle(
	xfs_mount_t				*mp,
	void					__user *arg,
	struct inode				*parinode)
{
	int					error;
	compat_xfs_attr_multiop_t		*ops;
	compat_xfs_fsop_attrmulti_handlereq_t	am_hreq;
	struct inode				*inode;
	unsigned int				i, size;
	char					*attr_name;

	if (!capable(CAP_SYS_ADMIN))
		return -XFS_ERROR(EPERM);
	if (copy_from_user(&am_hreq, arg,
			   sizeof(compat_xfs_fsop_attrmulti_handlereq_t)))
		return -XFS_ERROR(EFAULT);

	error = xfs_vget_fsop_handlereq_compat(mp, parinode, &am_hreq.hreq,
					       &inode);
	if (error)
		goto out;

	error = E2BIG;
	size = am_hreq.opcount * sizeof(compat_xfs_attr_multiop_t);
	if (!size || size > 16 * PAGE_SIZE)
		goto out_vn_rele;

	error = ENOMEM;
	ops = kmalloc(size, GFP_KERNEL);
	if (!ops)
		goto out_vn_rele;

	error = EFAULT;
	if (copy_from_user(ops, compat_ptr(am_hreq.ops), size))
		goto out_kfree_ops;

	attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL);
	if (!attr_name)
		goto out_kfree_ops;


	error = 0;
	for (i = 0; i < am_hreq.opcount; i++) {
		ops[i].am_error = strncpy_from_user(attr_name,
				compat_ptr(ops[i].am_attrname),
				MAXNAMELEN);
		if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN)
			error = -ERANGE;
		if (ops[i].am_error < 0)
			break;

		switch (ops[i].am_opcode) {
		case ATTR_OP_GET:
			ops[i].am_error = xfs_attrmulti_attr_get(inode,
					attr_name,
					compat_ptr(ops[i].am_attrvalue),
					&ops[i].am_length, ops[i].am_flags);
			break;
		case ATTR_OP_SET:
			ops[i].am_error = xfs_attrmulti_attr_set(inode,
					attr_name,
					compat_ptr(ops[i].am_attrvalue),
					ops[i].am_length, ops[i].am_flags);
			break;
		case ATTR_OP_REMOVE:
			ops[i].am_error = xfs_attrmulti_attr_remove(inode,
					attr_name, ops[i].am_flags);
			break;
		default:
			ops[i].am_error = EINVAL;
		}
	}

	if (copy_to_user(compat_ptr(am_hreq.ops), ops, size))
		error = XFS_ERROR(EFAULT);

	kfree(attr_name);
 out_kfree_ops:
	kfree(ops);
 out_vn_rele:
	iput(inode);
 out:
	return -error;
}

STATIC long
xfs_compat_ioctl(
	xfs_inode_t	*ip,
@@ -499,10 +586,7 @@ xfs_compat_ioctl(
	case XFS_IOC_GETBMAP:
	case XFS_IOC_GETBMAPA:
	case XFS_IOC_GETBMAPX:
/* not handled
	case XFS_IOC_FSSETDM_BY_HANDLE:
	case XFS_IOC_ATTRMULTI_BY_HANDLE:
*/
/*	case XFS_IOC_FSSETDM_BY_HANDLE: not handled */
	case XFS_IOC_FSCOUNTS:
	case XFS_IOC_SET_RESBLKS:
	case XFS_IOC_GET_RESBLKS:
@@ -610,6 +694,8 @@ xfs_compat_ioctl(
	}
	case XFS_IOC_ATTRLIST_BY_HANDLE_32:
		return xfs_compat_attrlist_by_handle(mp, arg, inode);
	case XFS_IOC_ATTRMULTI_BY_HANDLE_32:
		return xfs_compat_attrmulti_by_handle(mp, arg, inode);
	default:
		return -XFS_ERROR(ENOIOCTLCMD);
	}
+20 −0
Original line number Diff line number Diff line
@@ -135,6 +135,26 @@ typedef struct compat_xfs_fsop_attrlist_handlereq {
#define XFS_IOC_ATTRLIST_BY_HANDLE_32 \
	_IOW('X', 122, struct compat_xfs_fsop_attrlist_handlereq)

/* am_opcodes defined in xfs_fs.h */
typedef struct compat_xfs_attr_multiop {
	__u32		am_opcode;
	__s32		am_error;
	compat_uptr_t	am_attrname;
	compat_uptr_t	am_attrvalue;
	__u32		am_length;
	__u32		am_flags;
} compat_xfs_attr_multiop_t;

typedef struct compat_xfs_fsop_attrmulti_handlereq {
	struct compat_xfs_fsop_handlereq hreq; /* handle interface structure */
	__u32				opcount;/* count of following multiop */
	/* ptr to compat_xfs_attr_multiop */
	compat_uptr_t			ops; /* attr_multi data */
} compat_xfs_fsop_attrmulti_handlereq_t;

#define XFS_IOC_ATTRMULTI_BY_HANDLE_32 \
	_IOW('X', 123, struct compat_xfs_fsop_attrmulti_handlereq)

#ifdef BROKEN_X86_ALIGNMENT
/* on ia32 l_start is on a 32-bit boundary */
typedef struct compat_xfs_flock64 {