summaryrefslogtreecommitdiffstats
path: root/drivers/block/loop/loop_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/block/loop/loop_main.c')
-rw-r--r--drivers/block/loop/loop_main.c130
1 files changed, 120 insertions, 10 deletions
diff --git a/drivers/block/loop/loop_main.c b/drivers/block/loop/loop_main.c
index 1150956974fb..f37ed6e51a45 100644
--- a/drivers/block/loop/loop_main.c
+++ b/drivers/block/loop/loop_main.c
@@ -1146,9 +1146,22 @@ loop_set_status_old(struct loop_device *lo, const struct loop_info __user *arg)
{
struct loop_info info;
struct loop_info64 info64;
+ int err;
- if (copy_from_user(&info, arg, sizeof (struct loop_info)))
+ /* backward compatibility: copy everything except the file format type
+ * field */
+ err = copy_from_user(&info, arg,
+ sizeof(info) - sizeof(info.lo_file_fmt_type));
+ if (err)
return -EFAULT;
+
+ if (info.lo_flags & LO_FLAGS_FILE_FMT) {
+ /* copy everything from the user space */
+ err = copy_from_user(&info, arg, sizeof(info));
+ if (err)
+ return -EFAULT;
+ }
+
loop_info64_from_old(&info, &info64);
return loop_set_status(lo, &info64);
}
@@ -1157,9 +1170,22 @@ static int
loop_set_status64(struct loop_device *lo, const struct loop_info64 __user *arg)
{
struct loop_info64 info64;
+ int err;
- if (copy_from_user(&info64, arg, sizeof (struct loop_info64)))
+ /* backward compatibility: copy everything except the file format type
+ * field */
+ err = copy_from_user(&info64, arg,
+ sizeof(info64) - sizeof(info64.lo_file_fmt_type));
+ if (err)
return -EFAULT;
+
+ if (info64.lo_flags & LO_FLAGS_FILE_FMT) {
+ /* copy everything from the user space */
+ err = copy_from_user(&info64, arg, sizeof(info64));
+ if (err)
+ return -EFAULT;
+ }
+
return loop_set_status(lo, &info64);
}
@@ -1167,15 +1193,37 @@ static int
loop_get_status_old(struct loop_device *lo, struct loop_info __user *arg) {
struct loop_info info;
struct loop_info64 info64;
+ int lo_flags;
int err;
if (!arg)
return -EINVAL;
+
+ /* backward compatibility: copy everything except the file format type
+ * field */
+ err = copy_from_user(&info, arg,
+ sizeof(info) - sizeof(info.lo_file_fmt_type));
+ if (err)
+ return -EFAULT;
+
+ lo_flags = info.lo_flags;
+
err = loop_get_status(lo, &info64);
if (!err)
err = loop_info64_to_old(&info64, &info);
- if (!err && copy_to_user(arg, &info, sizeof(info)))
- err = -EFAULT;
+
+ if (lo_flags & LO_FLAGS_FILE_FMT) {
+ /* copy entire structure to user space because file format
+ * support is available */
+ err = copy_to_user(arg, &info, sizeof(info));
+ } else {
+ /* copy normal structure to user space */
+ err = copy_to_user(arg, &info,
+ sizeof(info) - sizeof(info.lo_file_fmt_type));
+ }
+
+ if (err)
+ return -EFAULT;
return err;
}
@@ -1183,13 +1231,37 @@ loop_get_status_old(struct loop_device *lo, struct loop_info __user *arg) {
static int
loop_get_status64(struct loop_device *lo, struct loop_info64 __user *arg) {
struct loop_info64 info64;
+ u32 lo_flags;
int err;
if (!arg)
return -EINVAL;
+
+ /* backward compatibility: copy everything except the file format type
+ * field */
+ err = copy_from_user(&info64, arg,
+ sizeof(info64) - sizeof(info64.lo_file_fmt_type));
+ if (err)
+ return -EFAULT;
+
+ lo_flags = info64.lo_flags;
+
err = loop_get_status(lo, &info64);
- if (!err && copy_to_user(arg, &info64, sizeof(info64)))
- err = -EFAULT;
+ if (err)
+ return -EFAULT;
+
+ if (lo_flags & LO_FLAGS_FILE_FMT) {
+ /* copy entire structure to user space because file format
+ * support is available */
+ err = copy_to_user(arg, &info64, sizeof(info64));
+ } else {
+ /* copy normal structure to user space */
+ err = copy_to_user(arg, &info64,
+ sizeof(info64) - sizeof(info64.lo_file_fmt_type));
+ }
+
+ if (err)
+ return -EFAULT;
return err;
}
@@ -1337,7 +1409,8 @@ struct compat_loop_info {
unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
compat_ulong_t lo_init[2];
char reserved[4];
-};
+ compat_int_t lo_file_fmt_type;
+} __attribute__((packed));
/*
* Transfer 32-bit compatibility structure in userspace to 64-bit loop info
@@ -1348,10 +1421,22 @@ loop_info64_from_compat(const struct compat_loop_info __user *arg,
struct loop_info64 *info64)
{
struct compat_loop_info info;
+ int err;
- if (copy_from_user(&info, arg, sizeof(info)))
+ /* backward compatibility: copy everything except the file format type
+ * field */
+ err = copy_from_user(&info, arg,
+ sizeof(info) - sizeof(info.lo_file_fmt_type));
+ if (err)
return -EFAULT;
+ if (info.lo_flags & LO_FLAGS_FILE_FMT) {
+ /* copy everything from the user space */
+ err = copy_from_user(&info, arg, sizeof(info));
+ if (err)
+ return -EFAULT;
+ }
+
memset(info64, 0, sizeof(*info64));
info64->lo_number = info.lo_number;
info64->lo_device = info.lo_device;
@@ -1364,6 +1449,7 @@ loop_info64_from_compat(const struct compat_loop_info __user *arg,
info64->lo_flags = info.lo_flags;
info64->lo_init[0] = info.lo_init[0];
info64->lo_init[1] = info.lo_init[1];
+ info64->lo_file_fmt_type = info.lo_file_fmt_type;
if (info.lo_encrypt_type == LO_CRYPT_CRYPTOAPI)
memcpy(info64->lo_crypt_name, info.lo_name, LO_NAME_SIZE);
else
@@ -1381,6 +1467,17 @@ loop_info64_to_compat(const struct loop_info64 *info64,
struct compat_loop_info __user *arg)
{
struct compat_loop_info info;
+ compat_int_t lo_flags;
+ int err;
+
+ /* backward compatibility: copy everything except the file format type
+ * field */
+ err = copy_from_user(&info, arg,
+ sizeof(info) - sizeof(info.lo_file_fmt_type));
+ if (err)
+ return -EFAULT;
+
+ lo_flags = info.lo_flags;
memset(&info, 0, sizeof(info));
info.lo_number = info64->lo_number;
@@ -1393,6 +1490,7 @@ loop_info64_to_compat(const struct loop_info64 *info64,
info.lo_flags = info64->lo_flags;
info.lo_init[0] = info64->lo_init[0];
info.lo_init[1] = info64->lo_init[1];
+ info.lo_file_fmt_type = info64->lo_file_fmt_type;
if (info.lo_encrypt_type == LO_CRYPT_CRYPTOAPI)
memcpy(info.lo_name, info64->lo_crypt_name, LO_NAME_SIZE);
else
@@ -1405,11 +1503,23 @@ loop_info64_to_compat(const struct loop_info64 *info64,
info.lo_inode != info64->lo_inode ||
info.lo_offset != info64->lo_offset ||
info.lo_init[0] != info64->lo_init[0] ||
- info.lo_init[1] != info64->lo_init[1])
+ info.lo_init[1] != info64->lo_init[1] ||
+ info.lo_file_fmt_type != info64->lo_file_fmt_type)
return -EOVERFLOW;
- if (copy_to_user(arg, &info, sizeof(info)))
+ if (lo_flags & LO_FLAGS_FILE_FMT) {
+ /* copy entire structure to user space because file format
+ * support is available */
+ err = copy_to_user(arg, &info, sizeof(info));
+ } else {
+ /* copy normal structure to user space */
+ err = copy_to_user(arg, &info,
+ sizeof(info) - sizeof(info.lo_file_fmt_type));
+ }
+
+ if (err)
return -EFAULT;
+
return 0;
}