History

dm ioctl: use kmalloc if possible

If the parameter buffer is small enough, try to allocate it with kmalloc() rather than vmalloc(). vmalloc is noticeably slower than kmalloc because it has to manipulate page tables. In my tests, on PA-RISC this patch speeds up activation 13 times. On Opteron this patch speeds up activation by 5%. This patch introduces a new function free_params() to free the parameters and this uses new flags that record whether or not vmalloc() was used and whether or not the input buffer must be wiped after use.

Mikulas Patocka committed 13 years ago

Commit 9c5091f1 parent 5023e5c1 file · +32 −13Browse files

Unified · Split

drivers/md/dm-ioctl.c+32−13
@@ -1543,7 +1543,21 @@ static int check_version(unsigned int cmd, struct dm_ioctl __user *user) · 1542 unmodified lines
15431543 return r;
15441544 }
15451545
1546−static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param)
1546+#define DM_PARAMS_VMALLOC 0x0001 /* Params alloced with vmalloc not kmalloc */
1547+#define DM_WIPE_BUFFER 0x0010 /* Wipe input buffer before returning from ioctl */
1548+
1549+static void free_params(struct dm_ioctl *param, size_t param_size, int param_flags)
1550+{
1551+ if (param_flags & DM_WIPE_BUFFER)
1552+ memset(param, 0, param_size);
1553+
1554+ if (param_flags & DM_PARAMS_VMALLOC)
1555+ vfree(param);
1556+ else
1557+ kfree(param);
1558+}
1559+
1560+static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param, int *param_flags)
15471561 {
15481562 struct dm_ioctl tmp, *dmi;
15491563 int secure_data;
@@ -1556,10 +1570,21 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) · 6 unmodified lines
15561570
15571571 secure_data = tmp.flags & DM_SECURE_DATA_FLAG;
15581572
1573+ *param_flags = secure_data ? DM_WIPE_BUFFER : 0;
1574+
15591575 /*
15601576 * Try to avoid low memory issues when a device is suspended.
1577+ * Use kmalloc() rather than vmalloc() when we can.
15611578 */
1562− dmi = __vmalloc(tmp.data_size, GFP_NOIO | __GFP_REPEAT | __GFP_HIGH, PAGE_KERNEL);
1579+ dmi = NULL;
1580+ if (tmp.data_size <= KMALLOC_MAX_SIZE)
1581+ dmi = kmalloc(tmp.data_size, GFP_NOIO | __GFP_NORETRY | __GFP_NOMEMALLOC | __GFP_NOWARN);
1582+
1583+ if (!dmi) {
1584+ dmi = __vmalloc(tmp.data_size, GFP_NOIO | __GFP_REPEAT | __GFP_HIGH, PAGE_KERNEL);
1585+ *param_flags |= DM_PARAMS_VMALLOC;
1586+ }
1587+
15631588 if (!dmi) {
15641589 if (secure_data && clear_user(user, tmp.data_size))
15651590 return -EFAULT;
@@ -1585,9 +1610,8 @@ static int copy_params(struct dm_ioctl __user *user, struct dm_ioctl **param) · 19 unmodified lines
15851610 return 0;
15861611
15871612 bad:
1588− if (secure_data)
1589− memset(dmi, 0, tmp.data_size);
1590− vfree(dmi);
1613+ free_params(dmi, tmp.data_size, *param_flags);
1614+
15911615 return -EFAULT;
15921616 }
15931617
@@ -1624,7 +1648,7 @@ static int validate_params(uint cmd, struct dm_ioctl *param) · 30 unmodified lines
16241648 static int ctl_ioctl(uint command, struct dm_ioctl __user *user)
16251649 {
16261650 int r = 0;
1627− int wipe_buffer;
1651+ int param_flags;
16281652 unsigned int cmd;
16291653 struct dm_ioctl *uninitialized_var(param);
16301654 ioctl_fn fn = NULL;
@@ -1662,14 +1686,12 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) · 31 unmodified lines
16621686 /*
16631687 * Copy the parameters into kernel space.
16641688 */
1665− r = copy_params(user, &param);
1689+ r = copy_params(user, &param, &param_flags);
16661690
16671691 if (r)
16681692 return r;
16691693
16701694 input_param_size = param->data_size;
1671− wipe_buffer = param->flags & DM_SECURE_DATA_FLAG;
1672−
16731695 r = validate_params(cmd, param);
16741696 if (r)
16751697 goto out;
@@ -1684,10 +1706,7 @@ static int ctl_ioctl(uint command, struct dm_ioctl __user *user) · 8 unmodified lines
16841706 r = -EFAULT;
16851707
16861708 out:
1687− if (wipe_buffer)
1688− memset(param, 0, input_param_size);
1689−
1690− vfree(param);
1709+ free_params(param, input_param_size, param_flags);
16911710 return r;
16921711 }
16931712