static unsigned int signal_poll(struct file * filp, struct poll_table_struct * poll) { struct xpmem_thread_group * seg_tg; struct xpmem_segment * seg; xpmem_segid_t segid; unsigned long irqs; unsigned int mask = 0; segid = (xpmem_segid_t)filp->private_data; seg_tg = xpmem_tg_ref_by_segid(segid); if (IS_ERR(seg_tg)) return PTR_ERR(seg_tg); seg = xpmem_seg_ref_by_segid(seg_tg, segid); if (IS_ERR(seg)) { xpmem_tg_deref(seg_tg); return PTR_ERR(seg); } poll_wait(filp, &(seg->signalled_wq), poll); irqs = atomic_read(&(seg->irq_count)); if (irqs > 0) mask = POLLIN | POLLRDNORM; xpmem_seg_deref(seg); xpmem_tg_deref(seg_tg); return mask; }
static ssize_t signal_write(struct file * filp, const char __user * buffer, size_t length, loff_t * offset) { struct xpmem_thread_group * seg_tg; struct xpmem_segment * seg; xpmem_segid_t segid; unsigned long irqs; unsigned long acks; int status; if (length != sizeof(unsigned long)) return -EINVAL; status = copy_from_user(&acks, buffer, sizeof(unsigned long)); if (status) return status; segid = (xpmem_segid_t)filp->private_data; seg_tg = xpmem_tg_ref_by_segid(segid); if (IS_ERR(seg_tg)) return PTR_ERR(seg_tg); seg = xpmem_seg_ref_by_segid(seg_tg, segid); if (IS_ERR(seg)) { xpmem_tg_deref(seg_tg); return PTR_ERR(seg); } irqs = atomic_read(&(seg->irq_count)); if (acks > irqs) acks = irqs; atomic_sub(acks, &(seg->irq_count)); xpmem_seg_deref(seg); xpmem_tg_deref(seg_tg); return length; }
static ssize_t signal_read(struct file * filp, char __user * buffer, size_t length, loff_t * offset) { struct xpmem_thread_group * seg_tg; struct xpmem_segment * seg; xpmem_segid_t segid; unsigned long irqs; int err; if (length != sizeof(unsigned long)) return -EINVAL; segid = (xpmem_segid_t)filp->private_data; seg_tg = xpmem_tg_ref_by_segid(segid); if (IS_ERR(seg_tg)) return PTR_ERR(seg_tg); seg = xpmem_seg_ref_by_segid(seg_tg, segid); if (IS_ERR(seg)) { xpmem_tg_deref(seg_tg); return PTR_ERR(seg); } /* Only ack if there are pending notifications */ err = (atomic_add_unless(&(seg->irq_count), -1, 0) == 0); irqs = atomic_read(&(seg->irq_count)); xpmem_seg_deref(seg); xpmem_tg_deref(seg_tg); if (err) return -ENODEV; if (copy_to_user(buffer, &irqs, sizeof(unsigned long))) return -EFAULT; return length; }
static ssize_t signal_read(struct file * filp, char __user * buffer, size_t length, loff_t * offset) { struct xpmem_thread_group * seg_tg; struct xpmem_segment * seg; xpmem_segid_t segid; unsigned long irqs; if (length != sizeof(unsigned long)) return -EINVAL; segid = (xpmem_segid_t)filp->private_data; seg_tg = xpmem_tg_ref_by_segid(segid); if (IS_ERR(seg_tg)) return PTR_ERR(seg_tg); seg = xpmem_seg_ref_by_segid(seg_tg, segid); if (IS_ERR(seg)) { xpmem_tg_deref(seg_tg); return PTR_ERR(seg); } wait_event_interruptible(seg->signalled_wq, (atomic_read(&(seg->irq_count)) > 0) ); irqs = atomic_read(&(seg->irq_count)); atomic_set(&(seg->irq_count), 0); xpmem_seg_deref(seg); xpmem_tg_deref(seg_tg); if (copy_to_user(buffer, &irqs, sizeof(unsigned long))) return -EFAULT; return length; }
int xpmem_segid_signal(xpmem_segid_t segid) { struct xpmem_thread_group * seg_tg; struct xpmem_segment * seg; seg_tg = xpmem_tg_ref_by_segid(segid); if (IS_ERR(seg_tg)) return PTR_ERR(seg_tg); seg = xpmem_seg_ref_by_segid(seg_tg, segid); if (IS_ERR(seg)) { xpmem_tg_deref(seg_tg); return PTR_ERR(seg); } xpmem_seg_signal(seg); xpmem_seg_deref(seg); xpmem_tg_deref(seg_tg); return 0; }
/* * Get permission to access a specified segid. */ int xpmem_get(xpmem_segid_t segid, int flags, int permit_type, void *permit_value, xpmem_apid_t *apid_p) { xpmem_apid_t apid = 0; int status = 0; int shadow_seg = 0; struct xpmem_segment *seg = NULL; struct xpmem_thread_group *ap_tg, *seg_tg; if (segid <= 0) return -EINVAL; if ((flags & ~(XPMEM_RDONLY | XPMEM_RDWR)) || (flags & (XPMEM_RDONLY | XPMEM_RDWR)) == (XPMEM_RDONLY | XPMEM_RDWR)) return -EINVAL; switch (permit_type) { case XPMEM_PERMIT_MODE: case XPMEM_GLOBAL_MODE: if (permit_value != NULL) return -EINVAL; break; default: return -EINVAL; } /* There are 2 cases that result in a remote lookup: * (1) The thread group encoded in the segment does not exist locally. * * (2) The thread group exists locally, but the segment does not. The * ids for thread groups are not globally unique, so it's possible that * the same thread group id exists in two separate enclaves, but only * one will own the segment */ seg_tg = xpmem_tg_ref_by_segid(segid); if (IS_ERR(seg_tg)) { seg_tg = xpmem_tg_ref_by_gid(current->aspace->id); if (IS_ERR(seg_tg)) return PTR_ERR(seg_tg); shadow_seg = 1; } if (!shadow_seg) { seg = xpmem_seg_ref_by_segid(seg_tg, segid); if (IS_ERR(seg)) shadow_seg = 1; } if (shadow_seg) { /* No local segment found. Look for a remote one */ /* NOTE: in either case, the tg has already been ref'd. We ref the * current process' tg if no tg is found for the segid */ status = xpmem_try_get_remote(seg_tg, segid, flags, permit_type, permit_value); if (status != 0) { xpmem_tg_deref(seg_tg); return status; } /* Now, get the shadow segment */ seg = xpmem_seg_ref_by_segid(seg_tg, segid); if (IS_ERR(seg)) { /* Error should be impossible here, but we'll * check anyway. The shadow segment was created in * xpmem_try_get_remote, so destroy it here */ xpmem_remove(segid); xpmem_tg_deref(seg_tg); return PTR_ERR(seg); } } /* find accessor's thread group structure */ ap_tg = xpmem_tg_ref_by_gid(current->aspace->id); if (IS_ERR(ap_tg)) { BUG_ON(PTR_ERR(ap_tg) != -ENOENT); status = -XPMEM_ERRNO_NOPROC; goto err_ap_tg; } apid = xpmem_make_apid(ap_tg); if (apid < 0) { status = apid; goto err_apid; } status = xpmem_get_segment(flags, permit_type, permit_value, apid, seg, seg_tg, ap_tg); if (status != 0) goto err_get; *apid_p = apid; xpmem_tg_deref(ap_tg); /* * The following two derefs * * xpmem_seg_deref(seg); * xpmem_tg_deref(seg_tg); * * aren't being done at this time in order to prevent the seg * and seg_tg structures from being prematurely kmem_free'd as long as the * potential for them to be referenced via this ap structure exists. * * These two derefs will be done by xpmem_release_ap() at the time * this ap structure is destroyed. */ return status; err_get: err_apid: xpmem_tg_deref(ap_tg); err_ap_tg: /* If we created a shadow segment, destroy it on error. Else, just * deref it */ if (shadow_seg) xpmem_remove(segid); else xpmem_seg_deref(seg); xpmem_tg_deref(seg_tg); return status; }