umd: Rename umd_info.cmdline umd_info.driver_name
[linux-block.git] / kernel / usermode_driver.c
CommitLineData
884c5e68
EB
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * umd - User mode driver support
4 */
5#include <linux/shmem_fs.h>
6#include <linux/pipe_fs_i.h>
7#include <linux/usermode_driver.h>
8
9static LIST_HEAD(umh_list);
10static DEFINE_MUTEX(umh_list_lock);
11
12static int umd_setup(struct subprocess_info *info, struct cred *new)
13{
74be2d3b 14 struct umd_info *umd_info = info->data;
884c5e68
EB
15 struct file *from_umh[2];
16 struct file *to_umh[2];
17 int err;
18
19 /* create pipe to send data to umh */
20 err = create_pipe_files(to_umh, 0);
21 if (err)
22 return err;
23 err = replace_fd(0, to_umh[0], 0);
24 fput(to_umh[0]);
25 if (err < 0) {
26 fput(to_umh[1]);
27 return err;
28 }
29
30 /* create pipe to receive data from umh */
31 err = create_pipe_files(from_umh, 0);
32 if (err) {
33 fput(to_umh[1]);
34 replace_fd(0, NULL, 0);
35 return err;
36 }
37 err = replace_fd(1, from_umh[1], 0);
38 fput(from_umh[1]);
39 if (err < 0) {
40 fput(to_umh[1]);
41 replace_fd(0, NULL, 0);
42 fput(from_umh[0]);
43 return err;
44 }
45
74be2d3b
EB
46 umd_info->pipe_to_umh = to_umh[1];
47 umd_info->pipe_from_umh = from_umh[0];
48 umd_info->pid = task_pid_nr(current);
884c5e68
EB
49 current->flags |= PF_UMH;
50 return 0;
51}
52
53static void umd_cleanup(struct subprocess_info *info)
54{
74be2d3b 55 struct umd_info *umd_info = info->data;
884c5e68
EB
56
57 /* cleanup if umh_setup() was successful but exec failed */
58 if (info->retval) {
74be2d3b
EB
59 fput(umd_info->pipe_to_umh);
60 fput(umd_info->pipe_from_umh);
884c5e68
EB
61 }
62}
63
64/**
65 * fork_usermode_blob - fork a blob of bytes as a usermode process
66 * @data: a blob of bytes that can be do_execv-ed as a file
67 * @len: length of the blob
68 * @info: information about usermode process (shouldn't be NULL)
69 *
884c5e68
EB
70 * Returns either negative error or zero which indicates success
71 * in executing a blob of bytes as a usermode process. In such
74be2d3b 72 * case 'struct umd_info *info' is populated with two pipes
884c5e68
EB
73 * and a pid of the process. The caller is responsible for health
74 * check of the user process, killing it via pid, and closing the
75 * pipes when user process is no longer needed.
76 */
74be2d3b 77int fork_usermode_blob(void *data, size_t len, struct umd_info *info)
884c5e68 78{
884c5e68
EB
79 struct subprocess_info *sub_info;
80 char **argv = NULL;
81 struct file *file;
82 ssize_t written;
83 loff_t pos = 0;
84 int err;
85
1199c6c3 86 file = shmem_kernel_file_setup(info->driver_name, len, 0);
884c5e68
EB
87 if (IS_ERR(file))
88 return PTR_ERR(file);
89
90 written = kernel_write(file, data, len, &pos);
91 if (written != len) {
92 err = written;
93 if (err >= 0)
94 err = -ENOMEM;
95 goto out;
96 }
97
98 err = -ENOMEM;
1199c6c3 99 argv = argv_split(GFP_KERNEL, info->driver_name, NULL);
884c5e68
EB
100 if (!argv)
101 goto out;
102
1199c6c3
EB
103 sub_info = call_usermodehelper_setup(info->driver_name, argv, NULL,
104 GFP_KERNEL,
884c5e68
EB
105 umd_setup, umd_cleanup, info);
106 if (!sub_info)
107 goto out;
108
109 sub_info->file = file;
110 err = call_usermodehelper_exec(sub_info, UMH_WAIT_EXEC);
111 if (!err) {
112 mutex_lock(&umh_list_lock);
113 list_add(&info->list, &umh_list);
114 mutex_unlock(&umh_list_lock);
115 }
116out:
117 if (argv)
118 argv_free(argv);
119 fput(file);
120 return err;
121}
122EXPORT_SYMBOL_GPL(fork_usermode_blob);
123
124void __exit_umh(struct task_struct *tsk)
125{
74be2d3b 126 struct umd_info *info;
884c5e68
EB
127 pid_t pid = tsk->pid;
128
129 mutex_lock(&umh_list_lock);
130 list_for_each_entry(info, &umh_list, list) {
131 if (info->pid == pid) {
132 list_del(&info->list);
133 mutex_unlock(&umh_list_lock);
134 goto out;
135 }
136 }
137 mutex_unlock(&umh_list_lock);
138 return;
139out:
140 if (info->cleanup)
141 info->cleanup(info);
142}
143