static int __sc_hcreate(struct task_struct *curr, struct pt_regs *regs) { unsigned log2psize; vrtx_hdesc_t hdesc; vrtxheap_t *heap; u_long heapsize; int err, hid; spl_t s; if (!__xn_access_ok (curr, VERIFY_WRITE, __xn_reg_arg3(regs), sizeof(hdesc))) return -EFAULT; /* Size of heap space. */ heapsize = __xn_reg_arg1(regs); /* Page size. */ log2psize = (int)__xn_reg_arg2(regs); hid = sc_hcreate(NULL, heapsize, log2psize, &err); if (err) return err; xnlock_get_irqsave(&nklock, s); heap = xnmap_fetch(vrtx_heap_idmap, hid); if (heap) { /* Paranoid. */ heap->mm = curr->mm; hdesc.hid = hid; hdesc.hcb = &heap->sysheap; hdesc.hsize = xnheap_extentsize(&heap->sysheap); xnlock_put_irqrestore(&nklock, s); __xn_copy_to_user(curr, (void __user *)__xn_reg_arg3(regs), &hdesc, sizeof(hdesc)); } else { xnlock_put_irqrestore(&nklock, s); err = ER_ID; } return err; }
/** * Truncate a file or shared memory object to a specified length. * * When used in kernel-space, this service set to @a len the size of a shared * memory object opened with the shm_open() service. In user-space this service * falls back to Linux regular ftruncate service for file descriptors not * obtained with shm_open(). When this service is used to increase the size of a * shared memory object, the added space is zero-filled. * * Shared memory are suitable for direct memory access (allocated in physically * contiguous memory) if O_DIRECT was passed to shm_open. * * Shared memory objects may only be resized if they are not currently mapped. * * @param fd file descriptor; * * @param len new length of the underlying file or shared memory object. * * @retval 0 on success; * @retval -1 with @a errno set if: * - EBADF, @a fd is not a valid file descriptor; * - EPERM, the caller context is invalid; * - EINVAL, the specified length is invalid; * - EINVAL, the architecture can not honour the O_DIRECT flag; * - EINTR, this service was interrupted by a signal; * - EBUSY, @a fd is a shared memory object descriptor and the underlying shared * memory is currently mapped; * - EFBIG, allocation of system memory failed. * * @par Valid contexts: * - kernel module initialization or cleanup routine; * - user-space thread (Xenomai threads switch to secondary mode). * * @see * <a href="http://www.opengroup.org/onlinepubs/000095399/functions/ftruncate.html"> * Specification.</a> * */ int ftruncate(int fd, off_t len) { unsigned desc_flags; pse51_desc_t *desc; pse51_shm_t *shm; int err; spl_t s; xnlock_get_irqsave(&nklock, s); shm = pse51_shm_get(&desc, fd, 1); if (IS_ERR(shm)) { err = -PTR_ERR(shm); xnlock_put_irqrestore(&nklock, s); goto error; } if (xnpod_asynch_p() || !xnpod_root_p()) { err = EPERM; xnlock_put_irqrestore(&nklock, s); goto err_shm_put; } if (len < 0) { err = EINVAL; xnlock_put_irqrestore(&nklock, s); goto err_shm_put; } desc_flags = pse51_desc_getflags(desc); xnlock_put_irqrestore(&nklock, s); if (down_interruptible(&shm->maplock)) { err = EINTR; goto err_shm_put; } /* Allocate one more page for alignment (the address returned by mmap must be aligned on a page boundary). */ if (len) #ifdef CONFIG_XENO_OPT_PERVASIVE len = xnheap_rounded_size(len + PAGE_SIZE, PAGE_SIZE); #else /* !CONFIG_XENO_OPT_PERVASIVE */ len = xnheap_rounded_size(len + PAGE_SIZE, XNHEAP_PAGE_SIZE); #endif /* !CONFIG_XENO_OPT_PERVASIVE */ err = 0; if (emptyq_p(&shm->mappings)) { /* Temporary storage, in order to preserve the memory contents upon resizing, if possible. */ void *addr = NULL; size_t size = 0; if (shm->addr) { if (len == xnheap_extentsize(&shm->heapbase)) { /* Size unchanged, skip copy and reinit. */ err = 0; goto err_up; } size = xnheap_max_contiguous(&shm->heapbase); addr = xnarch_alloc_host_mem(size); if (!addr) { err = ENOMEM; goto err_up; } memcpy(addr, shm->addr, size); xnheap_free(&shm->heapbase, shm->addr); xnheap_destroy_mapped(&shm->heapbase, NULL, NULL); shm->addr = NULL; shm->size = 0; } if (len) { int flags = XNARCH_SHARED_HEAP_FLAGS | ((desc_flags & O_DIRECT) ? GFP_DMA : 0); err = -xnheap_init_mapped(&shm->heapbase, len, flags); if (err) goto err_up; xnheap_set_label(&shm->heapbase, "posix shm: %s", shm->nodebase.name); shm->size = xnheap_max_contiguous(&shm->heapbase); shm->addr = xnheap_alloc(&shm->heapbase, shm->size); /* Required. */ memset(shm->addr, '\0', shm->size); /* Copy the previous contents. */ if (addr) memcpy(shm->addr, addr, shm->size < size ? shm->size : size); shm->size -= PAGE_SIZE; } if (addr) xnarch_free_host_mem(addr, size); } else if (len != xnheap_extentsize(&shm->heapbase)) err = EBUSY; err_up: up(&shm->maplock); err_shm_put: pse51_shm_put(shm, 1); if (!err) return 0; error: thread_set_errno(err == ENOMEM ? EFBIG : err); return -1; }
static int __sc_pcreate(struct task_struct *curr, struct pt_regs *regs) { u_long ptsize, bsize; vrtx_pdesc_t pdesc; xnheap_t *ptheap; vrtxpt_t *pt; int err, pid; char *ptaddr; spl_t s; if (!__xn_access_ok (curr, VERIFY_WRITE, __xn_reg_arg4(regs), sizeof(pdesc))) return -EFAULT; ptheap = (xnheap_t *)xnmalloc(sizeof(*ptheap)); if (!ptheap) return ER_MEM; /* Suggested partition ID. */ pid = __xn_reg_arg1(regs); /* Size of partition space -- account for the heap mgmt overhead. */ ptsize = __xn_reg_arg2(regs); /* Shared heaps use the natural page size (PAGE_SIZE) */ ptsize = xnheap_rounded_size(ptsize, PAGE_SIZE); /* Block size. */ bsize = __xn_reg_arg3(regs); err = xnheap_init_mapped(ptheap, ptsize, 0); if (err) goto free_heap; /* Allocate the partition space as a single shared heap block. */ ptaddr = xnheap_alloc(ptheap, ptsize); pid = sc_pcreate(pid, ptaddr, ptsize, bsize, &err); if (err) goto unmap_pt; xnlock_get_irqsave(&nklock, s); pt = xnmap_fetch(vrtx_pt_idmap, pid); if (pt) { /* Paranoid. */ pt->mm = curr->mm; pt->sysheap = ptheap; pdesc.pid = pid; pdesc.ptcb = ptheap; pdesc.ptsize = xnheap_extentsize(ptheap); xnlock_put_irqrestore(&nklock, s); __xn_copy_to_user(curr, (void __user *)__xn_reg_arg4(regs), &pdesc, sizeof(pdesc)); return 0; } xnlock_put_irqrestore(&nklock, s); err = ER_PID; unmap_pt: xnheap_destroy_mapped(ptheap, NULL, NULL); free_heap: xnfree(ptheap); return err; }