/* * Create a /dev/tpm%d and 'server side' file descriptor pair * * Return value: * Returns file pointer on success, an error value otherwise */ static struct file *vtpm_proxy_create_device( struct vtpm_proxy_new_dev *vtpm_new_dev) { struct proxy_dev *proxy_dev; int rc, fd; struct file *file; if (vtpm_new_dev->flags & ~VTPM_PROXY_FLAGS_ALL) return ERR_PTR(-EOPNOTSUPP); proxy_dev = vtpm_proxy_create_proxy_dev(); if (IS_ERR(proxy_dev)) return ERR_CAST(proxy_dev); proxy_dev->flags = vtpm_new_dev->flags; /* setup an anonymous file for the server-side */ fd = get_unused_fd_flags(O_RDWR); if (fd < 0) { rc = fd; goto err_delete_proxy_dev; } file = anon_inode_getfile("[vtpms]", &vtpm_proxy_fops, proxy_dev, O_RDWR); if (IS_ERR(file)) { rc = PTR_ERR(file); goto err_put_unused_fd; } /* from now on we can unwind with put_unused_fd() + fput() */ /* simulate an open() on the server side */ vtpm_proxy_fops_open(file); if (proxy_dev->flags & VTPM_PROXY_FLAG_TPM2) proxy_dev->chip->flags |= TPM_CHIP_FLAG_TPM2; vtpm_proxy_work_start(proxy_dev); vtpm_new_dev->fd = fd; vtpm_new_dev->major = MAJOR(proxy_dev->chip->dev.devt); vtpm_new_dev->minor = MINOR(proxy_dev->chip->dev.devt); vtpm_new_dev->tpm_num = proxy_dev->chip->dev_num; return file; err_put_unused_fd: put_unused_fd(fd); err_delete_proxy_dev: vtpm_proxy_delete_proxy_dev(proxy_dev); return ERR_PTR(rc); }
/* * Counter part to vtpm_create_device. */ static void vtpm_proxy_delete_device(struct proxy_dev *proxy_dev) { vtpm_proxy_work_stop(proxy_dev); /* * A client may hold the 'ops' lock, so let it know that the server * side shuts down before we try to grab the 'ops' lock when * unregistering the chip. */ vtpm_proxy_fops_undo_open(proxy_dev); tpm_chip_unregister(proxy_dev->chip); vtpm_proxy_delete_proxy_dev(proxy_dev); }