Print this page
OS-5223 removed shm segment is no longer available
Reviewed by: Bryan Cantrill <bryan@joyent.com>
Reviewed by: Patrick Mooney <patrick.mooney@joyent.com>
        
*** 19,28 ****
--- 19,29 ----
   * CDDL HEADER END
   */
  
  /*
   * Copyright (c) 1986, 2010, Oracle and/or its affiliates. All rights reserved.
+  * Copyright 2016 Joyent, Inc.
   */
  
  /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  /*        All Rights Reserved   */
  
*** 317,326 ****
--- 318,328 ----
                   */
                  uint_t  share_szc;
                  size_t  share_size;
                  struct  shm_data ssd;
                  uintptr_t align_hint;
+                 long    curprot;
  
                  /*
                   * Pick a share pagesize to use, if (!isspt(sp)).
                   * Otherwise use the already chosen page size.
                   *
*** 451,471 ****
                                  as_rangeunlock(as);
                                  goto errret;
                          }
                  }
  
                  if (!isspt(sp)) {
                          error = sptcreate(size, &segspt, sp->shm_amp, prot,
                              flags, share_szc);
                          if (error) {
                                  as_rangeunlock(as);
                                  goto errret;
                          }
                          sp->shm_sptinfo->sptas = segspt->s_as;
                          sp->shm_sptseg = segspt;
!                         sp->shm_sptprot = prot;
!                 } else if ((prot & sp->shm_sptprot) != sp->shm_sptprot) {
                          /*
                           * Ensure we're attaching to an ISM segment with
                           * fewer or equal permissions than what we're
                           * allowed.  Fail if the segment has more
                           * permissions than what we're allowed.
--- 453,474 ----
                                  as_rangeunlock(as);
                                  goto errret;
                          }
                  }
  
+                 curprot = sp->shm_opts & SHM_PROT_MASK;
                  if (!isspt(sp)) {
                          error = sptcreate(size, &segspt, sp->shm_amp, prot,
                              flags, share_szc);
                          if (error) {
                                  as_rangeunlock(as);
                                  goto errret;
                          }
                          sp->shm_sptinfo->sptas = segspt->s_as;
                          sp->shm_sptseg = segspt;
!                         sp->shm_opts = (sp->shm_opts & ~SHM_PROT_MASK) | prot;
!                 } else if ((prot & curprot) != curprot) {
                          /*
                           * Ensure we're attaching to an ISM segment with
                           * fewer or equal permissions than what we're
                           * allowed.  Fail if the segment has more
                           * permissions than what we're allowed.
*** 746,755 ****
--- 749,775 ----
                  if (sp->shm_lkcnt && (--sp->shm_lkcnt == 0)) {
                          shmem_unlock(sp, sp->shm_amp);
                  }
                  break;
  
+         /* Stage segment for removal, but don't remove until last detach */
+         case SHM_RMID:
+                 if ((error = secpolicy_ipc_owner(cr, (kipc_perm_t *)sp)) != 0)
+                         break;
+ 
+                 /*
+                  * If attached, just mark it as a pending remove, otherwise
+                  * we must perform the normal ipc_rmid now.
+                  */
+                 if ((sp->shm_perm.ipc_ref - 1) > 0) {
+                         sp->shm_opts |= SHM_RM_PENDING;
+                 } else {
+                         mutex_exit(lock);
+                         return (ipc_rmid(shm_svc, shmid, cr));
+                 }
+                 break;
+ 
          default:
                  error = EINVAL;
                  break;
          }
          mutex_exit(lock);
*** 776,785 ****
--- 796,822 ----
          (void) ipc_lock(shm_svc, sp->shm_perm.ipc_id);
          if (sap->sa_flags & SHMSA_ISM)
                  sp->shm_ismattch--;
          sp->shm_dtime = gethrestime_sec();
          sp->shm_lpid = pp->p_pid;
+         if ((sp->shm_opts & SHM_RM_PENDING) != 0 &&
+             sp->shm_perm.ipc_ref == 2) {
+                 /*
+                  * If this is the last detach of the segment across the whole
+                  * system then now we can perform the delayed IPC_RMID.
+                  * The ipc_ref count has 1 for the original 'get' and one for
+                  * each 'attach' (see 'stat' handling in shmctl).
+                  */
+                 sp->shm_opts &= ~SHM_RM_PENDING;
+                 mutex_enter(&shm_svc->ipcs_lock);
+                 ipc_rmsvc(shm_svc, (kipc_perm_t *)sp);  /* Drops lock */
+                 ASSERT(!MUTEX_HELD(&shm_svc->ipcs_lock));
+                 ASSERT(((kipc_perm_t *)sp)->ipc_ref > 0);
+ 
+                 /* Lock was dropped, need to retake it for following rele. */
+                 (void) ipc_lock(shm_svc, sp->shm_perm.ipc_id);
+         }
          ipc_rele(shm_svc, (kipc_perm_t *)sp);   /* Drops lock */
  
          kmem_free(sap, sizeof (segacct_t));
  }