summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.c6
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.h23
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl32.c94
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl32.h20
4 files changed, 136 insertions, 7 deletions
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index 498d3e15843b..c8f1e632ba94 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -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,
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.h b/fs/xfs/linux-2.6/xfs_ioctl.h
index 2df849f49a5e..f67dc69381e8 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.h
+++ b/fs/xfs/linux-2.6/xfs_ioctl.h
@@ -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
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.c b/fs/xfs/linux-2.6/xfs_ioctl32.c
index e7eb0d7e0d56..17993352aa64 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.c
@@ -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);
}
diff --git a/fs/xfs/linux-2.6/xfs_ioctl32.h b/fs/xfs/linux-2.6/xfs_ioctl32.h
index bbf3a2cd8a7d..785e7ec318cf 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl32.h
+++ b/fs/xfs/linux-2.6/xfs_ioctl32.h
@@ -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 {