+ /*
+ * attempt to allocate a new fp; if unsuccessful, the fp will be
+ * left unmodified (NULL).
+ */
+ error = falloc(p, &fp, &indx, vfs_context_current());
+ if (error)
+ goto bad;
+
+ /*
+ * We allocate a new entry if we are less than the maximum
+ * allowed and the one at the front of the LRU list is in use.
+ * Otherwise we use the one at the front of the LRU list.
+ */
+ MALLOC(pcp, struct psemcache *, sizeof(struct psemcache), M_SHM, M_WAITOK|M_ZERO);
+ if (pcp == PSEMCACHE_NULL) {
+ error = ENOMEM;
+ goto bad;
+ }
+
+ MALLOC(new_pinfo, struct pseminfo *, sizeof(struct pseminfo), M_SHM, M_WAITOK|M_ZERO);
+ if (new_pinfo == NULL) {
+ error = ENOSPC;
+ goto bad;
+ }
+#if CONFIG_MACF
+ mac_posixsem_label_init(new_pinfo);
+#endif
+
+ /*
+ * Provisionally create the semaphore in the new_pinfo; we have to do
+ * this here to prevent locking later. We use the value of kret to
+ * signal success or failure, which is why we set its default value
+ * to KERN_INVALID_ADDRESS, above.
+ */
+
+ fmode = FFLAGS(uap->oflag);
+
+ if((fmode & O_CREAT)) {
+
+ if((value < 0) || (value > SEM_VALUE_MAX)) {
+ error = EINVAL;
+ goto bad;
+ }
+
+ kret = semaphore_create(kernel_task, &new_pinfo->psem_semobject, SYNC_POLICY_FIFO, value);
+
+ if (kret != KERN_SUCCESS) {
+ switch (kret) {
+ case KERN_RESOURCE_SHORTAGE:
+ error = ENOMEM;
+ break;
+ case KERN_PROTECTION_FAILURE:
+ error = EACCES;
+ break;
+ default:
+ error = EINVAL;
+ }
+ goto bad;
+ }
+ }
+
+ MALLOC(new_pnode, struct psemnode *, sizeof(struct psemnode), M_SHM, M_WAITOK|M_ZERO);
+ if (new_pnode == NULL) {
+ error = ENOSPC;
+ goto bad;
+ }
+
+ PSEM_SUBSYS_LOCK();