forked from ~ljy/RK356X_SDK_RELEASE

hc
2023-12-11 072de836f53be56a70cecf70b43ae43b7ce17376
kernel/drivers/md/dm-ioctl.c
....@@ -17,6 +17,7 @@
1717 #include <linux/dm-ioctl.h>
1818 #include <linux/hdreg.h>
1919 #include <linux/compat.h>
20
+#include <linux/nospec.h>
2021
2122 #include <linux/uaccess.h>
2223
....@@ -572,7 +573,7 @@
572573 size_t *needed = needed_param;
573574
574575 *needed += sizeof(struct dm_target_versions);
575
- *needed += strlen(tt->name);
576
+ *needed += strlen(tt->name) + 1;
576577 *needed += ALIGN_MASK;
577578 }
578579
....@@ -601,17 +602,27 @@
601602 info->vers = align_ptr(((void *) ++info->vers) + strlen(tt->name) + 1);
602603 }
603604
604
-static int list_versions(struct file *filp, struct dm_ioctl *param, size_t param_size)
605
+static int __list_versions(struct dm_ioctl *param, size_t param_size, const char *name)
605606 {
606607 size_t len, needed = 0;
607608 struct dm_target_versions *vers;
608609 struct vers_iter iter_info;
610
+ struct target_type *tt = NULL;
611
+
612
+ if (name) {
613
+ tt = dm_get_target_type(name);
614
+ if (!tt)
615
+ return -EINVAL;
616
+ }
609617
610618 /*
611619 * Loop through all the devices working out how much
612620 * space we need.
613621 */
614
- dm_target_iterate(list_version_get_needed, &needed);
622
+ if (!tt)
623
+ dm_target_iterate(list_version_get_needed, &needed);
624
+ else
625
+ list_version_get_needed(tt, &needed);
615626
616627 /*
617628 * Grab our output buffer.
....@@ -627,16 +638,31 @@
627638 iter_info.old_vers = NULL;
628639 iter_info.vers = vers;
629640 iter_info.flags = 0;
630
- iter_info.end = (char *)vers+len;
641
+ iter_info.end = (char *)vers + needed;
631642
632643 /*
633644 * Now loop through filling out the names & versions.
634645 */
635
- dm_target_iterate(list_version_get_info, &iter_info);
646
+ if (!tt)
647
+ dm_target_iterate(list_version_get_info, &iter_info);
648
+ else
649
+ list_version_get_info(tt, &iter_info);
636650 param->flags |= iter_info.flags;
637651
638652 out:
653
+ if (tt)
654
+ dm_put_target_type(tt);
639655 return 0;
656
+}
657
+
658
+static int list_versions(struct file *filp, struct dm_ioctl *param, size_t param_size)
659
+{
660
+ return __list_versions(param, param_size, NULL);
661
+}
662
+
663
+static int get_target_version(struct file *filp, struct dm_ioctl *param, size_t param_size)
664
+{
665
+ return __list_versions(param, param_size, param->name);
640666 }
641667
642668 static int check_name(const char *name)
....@@ -1143,7 +1169,7 @@
11431169 spec->sector_start = ti->begin;
11441170 spec->length = ti->len;
11451171 strncpy(spec->target_type, ti->type->name,
1146
- sizeof(spec->target_type));
1172
+ sizeof(spec->target_type) - 1);
11471173
11481174 outptr += sizeof(struct dm_target_spec);
11491175 remaining = len - (outptr - outbuf);
....@@ -1446,7 +1472,7 @@
14461472 /*
14471473 * Check we have enough space.
14481474 */
1449
- needed = sizeof(*deps) + (sizeof(*deps->dev) * count);
1475
+ needed = struct_size(deps, dev, count);
14501476 if (len < needed) {
14511477 param->flags |= DM_BUFFER_FULL_FLAG;
14521478 return;
....@@ -1593,7 +1619,7 @@
15931619 }
15941620
15951621 ti = dm_table_find_target(table, tmsg->sector);
1596
- if (!dm_target_is_valid(ti)) {
1622
+ if (!ti) {
15971623 DMWARN("Target message sector outside device.");
15981624 r = -EINVAL;
15991625 } else if (ti->type->message)
....@@ -1665,11 +1691,13 @@
16651691 {DM_TARGET_MSG_CMD, 0, target_message},
16661692 {DM_DEV_SET_GEOMETRY_CMD, 0, dev_set_geometry},
16671693 {DM_DEV_ARM_POLL, IOCTL_FLAGS_NO_PARAMS, dev_arm_poll},
1694
+ {DM_GET_TARGET_VERSION, 0, get_target_version},
16681695 };
16691696
16701697 if (unlikely(cmd >= ARRAY_SIZE(_ioctls)))
16711698 return NULL;
16721699
1700
+ cmd = array_index_nospec(cmd, ARRAY_SIZE(_ioctls));
16731701 *ioctl_flags = _ioctls[cmd].flags;
16741702 return _ioctls[cmd].fn;
16751703 }
....@@ -1819,7 +1847,7 @@
18191847 int ioctl_flags;
18201848 int param_flags;
18211849 unsigned int cmd;
1822
- struct dm_ioctl *uninitialized_var(param);
1850
+ struct dm_ioctl *param;
18231851 ioctl_fn fn = NULL;
18241852 size_t input_param_size;
18251853 struct dm_ioctl param_kernel;
....@@ -2019,3 +2047,110 @@
20192047
20202048 return r;
20212049 }
2050
+EXPORT_SYMBOL_GPL(dm_copy_name_and_uuid);
2051
+
2052
+/**
2053
+ * dm_early_create - create a mapped device in early boot.
2054
+ *
2055
+ * @dmi: Contains main information of the device mapping to be created.
2056
+ * @spec_array: array of pointers to struct dm_target_spec. Describes the
2057
+ * mapping table of the device.
2058
+ * @target_params_array: array of strings with the parameters to a specific
2059
+ * target.
2060
+ *
2061
+ * Instead of having the struct dm_target_spec and the parameters for every
2062
+ * target embedded at the end of struct dm_ioctl (as performed in a normal
2063
+ * ioctl), pass them as arguments, so the caller doesn't need to serialize them.
2064
+ * The size of the spec_array and target_params_array is given by
2065
+ * @dmi->target_count.
2066
+ * This function is supposed to be called in early boot, so locking mechanisms
2067
+ * to protect against concurrent loads are not required.
2068
+ */
2069
+int __init dm_early_create(struct dm_ioctl *dmi,
2070
+ struct dm_target_spec **spec_array,
2071
+ char **target_params_array)
2072
+{
2073
+ int r, m = DM_ANY_MINOR;
2074
+ struct dm_table *t, *old_map;
2075
+ struct mapped_device *md;
2076
+ unsigned int i;
2077
+
2078
+ if (!dmi->target_count)
2079
+ return -EINVAL;
2080
+
2081
+ r = check_name(dmi->name);
2082
+ if (r)
2083
+ return r;
2084
+
2085
+ if (dmi->flags & DM_PERSISTENT_DEV_FLAG)
2086
+ m = MINOR(huge_decode_dev(dmi->dev));
2087
+
2088
+ /* alloc dm device */
2089
+ r = dm_create(m, &md);
2090
+ if (r)
2091
+ return r;
2092
+
2093
+ /* hash insert */
2094
+ r = dm_hash_insert(dmi->name, *dmi->uuid ? dmi->uuid : NULL, md);
2095
+ if (r)
2096
+ goto err_destroy_dm;
2097
+
2098
+ /* alloc table */
2099
+ r = dm_table_create(&t, get_mode(dmi), dmi->target_count, md);
2100
+ if (r)
2101
+ goto err_hash_remove;
2102
+
2103
+ /* add targets */
2104
+ for (i = 0; i < dmi->target_count; i++) {
2105
+ r = dm_table_add_target(t, spec_array[i]->target_type,
2106
+ (sector_t) spec_array[i]->sector_start,
2107
+ (sector_t) spec_array[i]->length,
2108
+ target_params_array[i]);
2109
+ if (r) {
2110
+ DMWARN("error adding target to table");
2111
+ goto err_destroy_table;
2112
+ }
2113
+ }
2114
+
2115
+ /* finish table */
2116
+ r = dm_table_complete(t);
2117
+ if (r)
2118
+ goto err_destroy_table;
2119
+
2120
+ md->type = dm_table_get_type(t);
2121
+ /* setup md->queue to reflect md's type (may block) */
2122
+ r = dm_setup_md_queue(md, t);
2123
+ if (r) {
2124
+ DMWARN("unable to set up device queue for new table.");
2125
+ goto err_destroy_table;
2126
+ }
2127
+
2128
+ /* Set new map */
2129
+ dm_suspend(md, 0);
2130
+ old_map = dm_swap_table(md, t);
2131
+ if (IS_ERR(old_map)) {
2132
+ r = PTR_ERR(old_map);
2133
+ goto err_destroy_table;
2134
+ }
2135
+ set_disk_ro(dm_disk(md), !!(dmi->flags & DM_READONLY_FLAG));
2136
+
2137
+ /* resume device */
2138
+ r = dm_resume(md);
2139
+ if (r)
2140
+ goto err_destroy_table;
2141
+
2142
+ DMINFO("%s (%s) is ready", md->disk->disk_name, dmi->name);
2143
+ dm_put(md);
2144
+ return 0;
2145
+
2146
+err_destroy_table:
2147
+ dm_table_destroy(t);
2148
+err_hash_remove:
2149
+ (void) __hash_remove(__get_name_cell(dmi->name));
2150
+ /* release reference from __get_name_cell */
2151
+ dm_put(md);
2152
+err_destroy_dm:
2153
+ dm_put(md);
2154
+ dm_destroy(md);
2155
+ return r;
2156
+}