Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v5.7 462 lines 11 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Intel MIC Platform Software Stack (MPSS) 4 * 5 * Copyright(c) 2014 Intel Corporation. 6 * 7 * Intel SCIF driver. 8 */ 9#include "scif_main.h" 10 11static int scif_fdopen(struct inode *inode, struct file *f) 12{ 13 struct scif_endpt *priv = scif_open(); 14 15 if (!priv) 16 return -ENOMEM; 17 f->private_data = priv; 18 return 0; 19} 20 21static int scif_fdclose(struct inode *inode, struct file *f) 22{ 23 struct scif_endpt *priv = f->private_data; 24 25 return scif_close(priv); 26} 27 28static int scif_fdmmap(struct file *f, struct vm_area_struct *vma) 29{ 30 struct scif_endpt *priv = f->private_data; 31 32 return scif_mmap(vma, priv); 33} 34 35static __poll_t scif_fdpoll(struct file *f, poll_table *wait) 36{ 37 struct scif_endpt *priv = f->private_data; 38 39 return __scif_pollfd(f, wait, priv); 40} 41 42static int scif_fdflush(struct file *f, fl_owner_t id) 43{ 44 struct scif_endpt *ep = f->private_data; 45 46 spin_lock(&ep->lock); 47 /* 48 * The listening endpoint stashes the open file information before 49 * waiting for incoming connections. The release callback would never be 50 * called if the application closed the endpoint, while waiting for 51 * incoming connections from a separate thread since the file descriptor 52 * reference count is bumped up in the accept IOCTL. Call the flush 53 * routine if the id matches the endpoint open file information so that 54 * the listening endpoint can be woken up and the fd released. 55 */ 56 if (ep->files == id) 57 __scif_flush(ep); 58 spin_unlock(&ep->lock); 59 return 0; 60} 61 62static __always_inline void scif_err_debug(int err, const char *str) 63{ 64 /* 65 * ENOTCONN is a common uninteresting error which is 66 * flooding debug messages to the console unnecessarily. 67 */ 68 if (err < 0 && err != -ENOTCONN) 69 dev_dbg(scif_info.mdev.this_device, "%s err %d\n", str, err); 70} 71 72static long scif_fdioctl(struct file *f, unsigned int cmd, unsigned long arg) 73{ 74 struct scif_endpt *priv = f->private_data; 75 void __user *argp = (void __user *)arg; 76 int err = 0; 77 struct scifioctl_msg request; 78 bool non_block = false; 79 80 non_block = !!(f->f_flags & O_NONBLOCK); 81 82 switch (cmd) { 83 case SCIF_BIND: 84 { 85 int pn; 86 87 if (copy_from_user(&pn, argp, sizeof(pn))) 88 return -EFAULT; 89 90 pn = scif_bind(priv, pn); 91 if (pn < 0) 92 return pn; 93 94 if (copy_to_user(argp, &pn, sizeof(pn))) 95 return -EFAULT; 96 97 return 0; 98 } 99 case SCIF_LISTEN: 100 return scif_listen(priv, arg); 101 case SCIF_CONNECT: 102 { 103 struct scifioctl_connect req; 104 struct scif_endpt *ep = (struct scif_endpt *)priv; 105 106 if (copy_from_user(&req, argp, sizeof(req))) 107 return -EFAULT; 108 109 err = __scif_connect(priv, &req.peer, non_block); 110 if (err < 0) 111 return err; 112 113 req.self.node = ep->port.node; 114 req.self.port = ep->port.port; 115 116 if (copy_to_user(argp, &req, sizeof(req))) 117 return -EFAULT; 118 119 return 0; 120 } 121 /* 122 * Accept is done in two halves. The request ioctl does the basic 123 * functionality of accepting the request and returning the information 124 * about it including the internal ID of the end point. The register 125 * is done with the internal ID on a new file descriptor opened by the 126 * requesting process. 127 */ 128 case SCIF_ACCEPTREQ: 129 { 130 struct scifioctl_accept request; 131 scif_epd_t *ep = (scif_epd_t *)&request.endpt; 132 133 if (copy_from_user(&request, argp, sizeof(request))) 134 return -EFAULT; 135 136 err = scif_accept(priv, &request.peer, ep, request.flags); 137 if (err < 0) 138 return err; 139 140 if (copy_to_user(argp, &request, sizeof(request))) { 141 scif_close(*ep); 142 return -EFAULT; 143 } 144 /* 145 * Add to the list of user mode eps where the second half 146 * of the accept is not yet completed. 147 */ 148 mutex_lock(&scif_info.eplock); 149 list_add_tail(&((*ep)->miacceptlist), &scif_info.uaccept); 150 list_add_tail(&((*ep)->liacceptlist), &priv->li_accept); 151 (*ep)->listenep = priv; 152 priv->acceptcnt++; 153 mutex_unlock(&scif_info.eplock); 154 155 return 0; 156 } 157 case SCIF_ACCEPTREG: 158 { 159 struct scif_endpt *priv = f->private_data; 160 struct scif_endpt *newep; 161 struct scif_endpt *lisep; 162 struct scif_endpt *fep = NULL; 163 struct scif_endpt *tmpep; 164 struct list_head *pos, *tmpq; 165 166 /* Finally replace the pointer to the accepted endpoint */ 167 if (copy_from_user(&newep, argp, sizeof(void *))) 168 return -EFAULT; 169 170 /* Remove form the user accept queue */ 171 mutex_lock(&scif_info.eplock); 172 list_for_each_safe(pos, tmpq, &scif_info.uaccept) { 173 tmpep = list_entry(pos, 174 struct scif_endpt, miacceptlist); 175 if (tmpep == newep) { 176 list_del(pos); 177 fep = tmpep; 178 break; 179 } 180 } 181 182 if (!fep) { 183 mutex_unlock(&scif_info.eplock); 184 return -ENOENT; 185 } 186 187 lisep = newep->listenep; 188 list_for_each_safe(pos, tmpq, &lisep->li_accept) { 189 tmpep = list_entry(pos, 190 struct scif_endpt, liacceptlist); 191 if (tmpep == newep) { 192 list_del(pos); 193 lisep->acceptcnt--; 194 break; 195 } 196 } 197 198 mutex_unlock(&scif_info.eplock); 199 200 /* Free the resources automatically created from the open. */ 201 scif_anon_inode_fput(priv); 202 scif_teardown_ep(priv); 203 scif_add_epd_to_zombie_list(priv, !SCIF_EPLOCK_HELD); 204 f->private_data = newep; 205 return 0; 206 } 207 case SCIF_SEND: 208 { 209 struct scif_endpt *priv = f->private_data; 210 211 if (copy_from_user(&request, argp, 212 sizeof(struct scifioctl_msg))) { 213 err = -EFAULT; 214 goto send_err; 215 } 216 err = scif_user_send(priv, (void __user *)request.msg, 217 request.len, request.flags); 218 if (err < 0) 219 goto send_err; 220 if (copy_to_user(& 221 ((struct scifioctl_msg __user *)argp)->out_len, 222 &err, sizeof(err))) { 223 err = -EFAULT; 224 goto send_err; 225 } 226 err = 0; 227send_err: 228 scif_err_debug(err, "scif_send"); 229 return err; 230 } 231 case SCIF_RECV: 232 { 233 struct scif_endpt *priv = f->private_data; 234 235 if (copy_from_user(&request, argp, 236 sizeof(struct scifioctl_msg))) { 237 err = -EFAULT; 238 goto recv_err; 239 } 240 241 err = scif_user_recv(priv, (void __user *)request.msg, 242 request.len, request.flags); 243 if (err < 0) 244 goto recv_err; 245 246 if (copy_to_user(& 247 ((struct scifioctl_msg __user *)argp)->out_len, 248 &err, sizeof(err))) { 249 err = -EFAULT; 250 goto recv_err; 251 } 252 err = 0; 253recv_err: 254 scif_err_debug(err, "scif_recv"); 255 return err; 256 } 257 case SCIF_GET_NODEIDS: 258 { 259 struct scifioctl_node_ids node_ids; 260 int entries; 261 u16 *nodes; 262 void __user *unodes, *uself; 263 u16 self; 264 265 if (copy_from_user(&node_ids, argp, sizeof(node_ids))) { 266 err = -EFAULT; 267 goto getnodes_err2; 268 } 269 270 entries = min_t(int, scif_info.maxid, node_ids.len); 271 nodes = kmalloc_array(entries, sizeof(u16), GFP_KERNEL); 272 if (entries && !nodes) { 273 err = -ENOMEM; 274 goto getnodes_err2; 275 } 276 node_ids.len = scif_get_node_ids(nodes, entries, &self); 277 278 unodes = (void __user *)node_ids.nodes; 279 if (copy_to_user(unodes, nodes, sizeof(u16) * entries)) { 280 err = -EFAULT; 281 goto getnodes_err1; 282 } 283 284 uself = (void __user *)node_ids.self; 285 if (copy_to_user(uself, &self, sizeof(u16))) { 286 err = -EFAULT; 287 goto getnodes_err1; 288 } 289 290 if (copy_to_user(argp, &node_ids, sizeof(node_ids))) { 291 err = -EFAULT; 292 goto getnodes_err1; 293 } 294getnodes_err1: 295 kfree(nodes); 296getnodes_err2: 297 return err; 298 } 299 case SCIF_REG: 300 { 301 struct scif_endpt *priv = f->private_data; 302 struct scifioctl_reg reg; 303 off_t ret; 304 305 if (copy_from_user(&reg, argp, sizeof(reg))) { 306 err = -EFAULT; 307 goto reg_err; 308 } 309 if (reg.flags & SCIF_MAP_KERNEL) { 310 err = -EINVAL; 311 goto reg_err; 312 } 313 ret = scif_register(priv, (void *)reg.addr, reg.len, 314 reg.offset, reg.prot, reg.flags); 315 if (ret < 0) { 316 err = (int)ret; 317 goto reg_err; 318 } 319 320 if (copy_to_user(&((struct scifioctl_reg __user *)argp) 321 ->out_offset, &ret, sizeof(reg.out_offset))) { 322 err = -EFAULT; 323 goto reg_err; 324 } 325 err = 0; 326reg_err: 327 scif_err_debug(err, "scif_register"); 328 return err; 329 } 330 case SCIF_UNREG: 331 { 332 struct scif_endpt *priv = f->private_data; 333 struct scifioctl_unreg unreg; 334 335 if (copy_from_user(&unreg, argp, sizeof(unreg))) { 336 err = -EFAULT; 337 goto unreg_err; 338 } 339 err = scif_unregister(priv, unreg.offset, unreg.len); 340unreg_err: 341 scif_err_debug(err, "scif_unregister"); 342 return err; 343 } 344 case SCIF_READFROM: 345 { 346 struct scif_endpt *priv = f->private_data; 347 struct scifioctl_copy copy; 348 349 if (copy_from_user(&copy, argp, sizeof(copy))) { 350 err = -EFAULT; 351 goto readfrom_err; 352 } 353 err = scif_readfrom(priv, copy.loffset, copy.len, copy.roffset, 354 copy.flags); 355readfrom_err: 356 scif_err_debug(err, "scif_readfrom"); 357 return err; 358 } 359 case SCIF_WRITETO: 360 { 361 struct scif_endpt *priv = f->private_data; 362 struct scifioctl_copy copy; 363 364 if (copy_from_user(&copy, argp, sizeof(copy))) { 365 err = -EFAULT; 366 goto writeto_err; 367 } 368 err = scif_writeto(priv, copy.loffset, copy.len, copy.roffset, 369 copy.flags); 370writeto_err: 371 scif_err_debug(err, "scif_writeto"); 372 return err; 373 } 374 case SCIF_VREADFROM: 375 { 376 struct scif_endpt *priv = f->private_data; 377 struct scifioctl_copy copy; 378 379 if (copy_from_user(&copy, argp, sizeof(copy))) { 380 err = -EFAULT; 381 goto vreadfrom_err; 382 } 383 err = scif_vreadfrom(priv, (void __force *)copy.addr, copy.len, 384 copy.roffset, copy.flags); 385vreadfrom_err: 386 scif_err_debug(err, "scif_vreadfrom"); 387 return err; 388 } 389 case SCIF_VWRITETO: 390 { 391 struct scif_endpt *priv = f->private_data; 392 struct scifioctl_copy copy; 393 394 if (copy_from_user(&copy, argp, sizeof(copy))) { 395 err = -EFAULT; 396 goto vwriteto_err; 397 } 398 err = scif_vwriteto(priv, (void __force *)copy.addr, copy.len, 399 copy.roffset, copy.flags); 400vwriteto_err: 401 scif_err_debug(err, "scif_vwriteto"); 402 return err; 403 } 404 case SCIF_FENCE_MARK: 405 { 406 struct scif_endpt *priv = f->private_data; 407 struct scifioctl_fence_mark mark; 408 int tmp_mark = 0; 409 410 if (copy_from_user(&mark, argp, sizeof(mark))) { 411 err = -EFAULT; 412 goto fence_mark_err; 413 } 414 err = scif_fence_mark(priv, mark.flags, &tmp_mark); 415 if (err) 416 goto fence_mark_err; 417 if (copy_to_user((void __user *)mark.mark, &tmp_mark, 418 sizeof(tmp_mark))) { 419 err = -EFAULT; 420 goto fence_mark_err; 421 } 422fence_mark_err: 423 scif_err_debug(err, "scif_fence_mark"); 424 return err; 425 } 426 case SCIF_FENCE_WAIT: 427 { 428 struct scif_endpt *priv = f->private_data; 429 430 err = scif_fence_wait(priv, arg); 431 scif_err_debug(err, "scif_fence_wait"); 432 return err; 433 } 434 case SCIF_FENCE_SIGNAL: 435 { 436 struct scif_endpt *priv = f->private_data; 437 struct scifioctl_fence_signal signal; 438 439 if (copy_from_user(&signal, argp, sizeof(signal))) { 440 err = -EFAULT; 441 goto fence_signal_err; 442 } 443 444 err = scif_fence_signal(priv, signal.loff, signal.lval, 445 signal.roff, signal.rval, signal.flags); 446fence_signal_err: 447 scif_err_debug(err, "scif_fence_signal"); 448 return err; 449 } 450 } 451 return -EINVAL; 452} 453 454const struct file_operations scif_fops = { 455 .open = scif_fdopen, 456 .release = scif_fdclose, 457 .unlocked_ioctl = scif_fdioctl, 458 .mmap = scif_fdmmap, 459 .poll = scif_fdpoll, 460 .flush = scif_fdflush, 461 .owner = THIS_MODULE, 462};