/*
* vlds.c: Sun4v LDOMs Virtual Domain Services Driver
*
- * Copyright (C) 2015 Oracle. All rights reserved.
+ * Copyright (C) 2015, 2016 Oracle. All rights reserved.
*/
#include <linux/cdev.h>
#include <linux/device.h>
}
-static int vlds_add_event(pid_t tgid, struct vlds_service_info *svc_info,
- u64 type, vlds_ver_t *neg_vers)
+static int vlds_signal_event(pid_t tgid, int fd)
{
- struct vlds_event_info *event_info;
- struct vlds_event *event;
- struct task_struct *utask;
struct file *efd_file;
struct eventfd_ctx *efd_ctx;
- int rv;
-
- mutex_lock(&vlds_event_info_list_mutex);
-
- event_info = NULL;
- rv = vlds_get_event_info(tgid, &event_info);
- if (rv || event_info == NULL) {
- /*
- * If we failed to find an event_info, it probably just
- * means the process did not register for events in favor
- * of using polling - which is valid.
- */
- mutex_unlock(&vlds_event_info_list_mutex);
- return 0;
- }
-
- event = kzalloc(sizeof(struct vlds_event), GFP_KERNEL);
- if (unlikely(event == NULL)) {
- dprintk("failed to allocate event for "
- "service %llx\n", svc_info->handle);
- mutex_unlock(&vlds_event_info_list_mutex);
- return -ENOMEM;
- } else {
- event->type = type;
- event->svc_info = svc_info;
- if (neg_vers != NULL)
- event->neg_vers = *neg_vers;
-
- list_add_tail(&event->list,
- &event_info->event_list);
- }
-
- mutex_unlock(&vlds_event_info_list_mutex);
+ struct task_struct *utask;
/*
* Signal the process that there is an event pending
return -EIO;
}
- /* Get the file corresponding to event_info->fd */
- efd_file = fcheck_files(utask->files, event_info->fd);
+ /* Get the file corresponding to fd */
+ efd_file = fcheck_files(utask->files, fd);
if (!efd_file) {
rcu_read_unlock();
return -EIO;
rcu_read_unlock();
+ return 0;
+}
+
+/* vlds_dev_mutex must be held */
+static void vlds_add_event_all(struct vlds_dev *vlds, u64 type)
+{
+ struct vlds_event_info *event_info;
+ struct vlds_event *event;
+ int rv;
+
+ mutex_lock(&vlds_event_info_list_mutex);
+
+ list_for_each_entry(event_info, &vlds_event_info_list, list) {
+
+ event = kzalloc(sizeof(struct vlds_event), GFP_KERNEL);
+ if (unlikely(event == NULL)) {
+ dprintk("failed to allocate event %llu for tgid=%u\n",
+ type, event_info->tgid);
+ } else {
+ event->type = type;
+ list_add_tail(&event->list,
+ &event_info->event_list);
+ }
+
+ rv = vlds_signal_event(event_info->tgid, event_info->fd);
+ if (rv) {
+ /* just give an error if we failed to add the event */
+ pr_err("%s: Failed to create %llu event for tgid=%u\n",
+ vlds->int_name, type, event_info->tgid);
+ }
+ }
+
+ mutex_unlock(&vlds_event_info_list_mutex);
+}
+
+static int vlds_add_svc_event(pid_t tgid, struct vlds_service_info *svc_info,
+ u64 type, vlds_ver_t *neg_vers)
+{
+ struct vlds_event_info *event_info;
+ struct vlds_event *event;
+ int rv;
+
+ mutex_lock(&vlds_event_info_list_mutex);
+
+ event_info = NULL;
+ rv = vlds_get_event_info(tgid, &event_info);
+ if (rv || event_info == NULL) {
+ /*
+ * If we failed to find an event_info, it probably just
+ * means the process did not register for events in favor
+ * of using polling - which is valid.
+ */
+ mutex_unlock(&vlds_event_info_list_mutex);
+ return 0;
+ }
+
+ event = kzalloc(sizeof(struct vlds_event), GFP_KERNEL);
+ if (unlikely(event == NULL)) {
+ if (svc_info)
+ dprintk("failed to allocate event for "
+ "service %llx\n", svc_info->handle);
+ mutex_unlock(&vlds_event_info_list_mutex);
+ return -ENOMEM;
+ }
+
+ event->type = type;
+ event->svc_info = svc_info;
+ if (neg_vers != NULL)
+ event->neg_vers = *neg_vers;
+
+ list_add_tail(&event->list,
+ &event_info->event_list);
+
+ rv = vlds_signal_event(tgid, event_info->fd);
+
+ mutex_unlock(&vlds_event_info_list_mutex);
+
return rv;
}
/* vlds_dev_mutex must be held */
-static void vlds_add_event_all(struct vlds_dev *vlds,
+static void vlds_add_event_svc_all(struct vlds_dev *vlds,
struct vlds_service_info *svc_info, u64 type, vlds_ver_t *neg_vers)
{
struct vlds_tgid_info *tgid_info;
if (!tgid_info->event_reg)
continue;
- rv = vlds_add_event(tgid_info->tgid, svc_info,
+ rv = vlds_add_svc_event(tgid_info->tgid, svc_info,
type, neg_vers);
if (rv) {
/* just give an error if we failed to add the event */
if (rv == 0 && event_info != NULL) {
list_for_each_entry_safe(event, next, &event_info->event_list,
list) {
- if (event->svc_info == svc_info)
+ if (event->svc_info && event->svc_info == svc_info)
vlds_remove_event(event_info, event);
}
}
* For every process that has registered this service
* in EVENT mode, register an event.
*/
- vlds_add_event_all(vlds, svc_info, VLDS_EVENT_TYPE_REG,
+ vlds_add_event_svc_all(vlds, svc_info, VLDS_EVENT_TYPE_REG,
&svc_info->neg_vers);
dprintk("%s: service %s register version (%u.%u) hdl=%llx\n",
* For every process that has registered this service
* in EVENT mode, register an event.
*/
- vlds_add_event_all(vlds, svc_info, VLDS_EVENT_TYPE_UNREG, NULL);
+ vlds_add_event_svc_all(vlds, svc_info, VLDS_EVENT_TYPE_UNREG, NULL);
dprintk("%s: service %s unregister hdl=%llx\n",
vlds->int_name, svc_info->name, hdl);
* For every process that has registered this service
* in EVENT mode, register an event.
*/
- vlds_add_event_all(vlds, svc_info, VLDS_EVENT_TYPE_DATA, NULL);
+ vlds_add_event_svc_all(vlds, svc_info, VLDS_EVENT_TYPE_DATA, NULL);
dprintk("%s: service %s: Received %lu bytes hdl=%llx\n",
vlds->int_name, svc_info->name, buflen, hdl);
*/
if (is_event_reg &&
svc_info->state == VLDS_HDL_STATE_CONNECTED) {
- rv = vlds_add_event(tgid, svc_info,
+ rv = vlds_add_svc_event(tgid, svc_info,
VLDS_EVENT_TYPE_REG, &svc_info->neg_vers);
if (rv) {
/* just give an error if add event fails */
}
/* populate the return event handle */
- if (put_user(event->svc_info->handle,
- (u64 __user *)(next_event.vlds_hdlp)) != 0) {
- rv = -EFAULT;
- goto error_out2;
+ if (event->svc_info) {
+ if (put_user(event->svc_info->handle,
+ (u64 __user *)(next_event.vlds_hdlp)) != 0) {
+ rv = -EFAULT;
+ goto error_out2;
+ }
}
/* populate the return event type */
dev_set_drvdata(&vdev->dev, vlds);
+ mutex_lock(&vlds->vlds_mutex);
+ /* Register a device update event */
+ vlds_add_event_all(vlds, VLDS_EVENT_TYPE_DEVICE_UPDATE);
+ mutex_unlock(&vlds->vlds_mutex);
+
dprintk("%s: Probe successfful: cfg_handle=%llu, id=%llu\n",
vlds->int_name, vdev->dev_no, *id);
device_destroy(vlds_data.chrdev_class, vlds->devt);
cdev_del(&vlds->cdev);
+ /* Register a device update event */
+ vlds_add_event_all(vlds, VLDS_EVENT_TYPE_DEVICE_UPDATE);
+
/*
* If there are still outstanding references (opens)
* on this device, then set a flag and remove it on