1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 #include <sys/param.h>
  27 #include <sys/types.h>
  28 #include <sys/pathname.h>
  29 #include <sys/errno.h>
  30 #include <sys/cmn_err.h>
  31 #include <sys/debug.h>
  32 #include <sys/systm.h>
  33 #include <sys/unistd.h>
  34 #include <sys/door.h>
  35 #include <sys/socket.h>
  36 #include <nfs/export.h>
  37 #include <nfs/nfs_cmd.h>
  38 #include <sys/kmem.h>
  39 #include <sys/sunddi.h>
  40 
  41 #define NFSCMD_DR_TRYCNT        8
  42 
  43 #ifdef nextdp
  44 #undef nextdp
  45 #endif
  46 #define nextdp(dp)      ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
  47 
  48 kmutex_t        nfscmd_lock;
  49 door_handle_t   nfscmd_dh;
  50 
  51 static struct charset_cache *nfscmd_charmap(exportinfo_t *exi,
  52     struct sockaddr *sp);
  53 
  54 
  55 void
  56 nfscmd_args(uint_t did)
  57 {
  58         mutex_enter(&nfscmd_lock);
  59         if (nfscmd_dh)
  60                 door_ki_rele(nfscmd_dh);
  61         nfscmd_dh = door_ki_lookup(did);
  62         mutex_exit(&nfscmd_lock);
  63 }
  64 
  65 void
  66 nfscmd_init(void)
  67 {
  68         mutex_init(&nfscmd_lock, NULL, MUTEX_DEFAULT, NULL);
  69 }
  70 
  71 void
  72 nfscmd_fini(void)
  73 {
  74 }
  75 
  76 /*
  77  * nfscmd_send(arg, result)
  78  *
  79  * Send a command to the daemon listening on the door. The result is
  80  * returned in the result pointer if the function return value is
  81  * NFSCMD_ERR_SUCCESS. Otherwise it is the error value.
  82  */
  83 int
  84 nfscmd_send(nfscmd_arg_t *arg, nfscmd_res_t *res)
  85 {
  86         door_handle_t   dh;
  87         door_arg_t      da;
  88         door_info_t     di;
  89         int             ntries = 0;
  90         int             last = 0;
  91 
  92 retry:
  93         mutex_enter(&nfscmd_lock);
  94         dh = nfscmd_dh;
  95         if (dh != NULL)
  96                 door_ki_hold(dh);
  97         mutex_exit(&nfscmd_lock);
  98 
  99         if (dh == NULL) {
 100                 /*
 101                  * The rendezvous point has not been established yet !
 102                  * This could mean that either mountd(1m) has not yet
 103                  * been started or that _this_ routine nuked the door
 104                  * handle after receiving an EINTR for a REVOKED door.
 105                  *
 106                  * Returning NFSAUTH_DROP will cause the NFS client
 107                  * to retransmit the request, so let's try to be more
 108                  * rescillient and attempt for ntries before we bail.
 109                  */
 110                 if (++ntries % NFSCMD_DR_TRYCNT) {
 111                         delay(hz);
 112                         goto retry;
 113                 }
 114                 return (NFSCMD_ERR_DROP);
 115         }
 116 
 117         da.data_ptr = (char *)arg;
 
 124         switch (door_ki_upcall(dh, &da)) {
 125         case 0:
 126                 /* Success */
 127                 break;
 128         case EAGAIN:
 129                 /* Need to retry a couple of times */
 130                 door_ki_rele(dh);
 131                 delay(hz);
 132                 goto retry;
 133                 /* NOTREACHED */
 134         case EINTR:
 135                 if (!door_ki_info(dh, &di)) {
 136                         if (di.di_attributes & DOOR_REVOKED) {
 137                                 /*
 138                                  * The server barfed and revoked
 139                                  * the (existing) door on us; we
 140                                  * want to wait to give smf(5) a
 141                                  * chance to restart mountd(1m)
 142                                  * and establish a new door handle.
 143                                  */
 144                                 mutex_enter(&nfscmd_lock);
 145                                 if (dh == nfscmd_dh)
 146                                         nfscmd_dh = NULL;
 147                                 mutex_exit(&nfscmd_lock);
 148                                 door_ki_rele(dh);
 149                                 delay(hz);
 150                                 goto retry;
 151                         }
 152                         /*
 153                          * If the door was _not_ revoked on us,
 154                          * then more than likely we took an INTR,
 155                          * so we need to fail the operation.
 156                          */
 157                         door_ki_rele(dh);
 158                 }
 159                 /*
 160                  * The only failure that can occur from getting
 161                  * the door info is EINVAL, so we let the code
 162                  * below handle it.
 163                  */
 164                 /* FALLTHROUGH */
 165 
 166         case EBADF:
 167         case EINVAL:
 
 | 
   1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright 2018 Nexenta Systems, Inc.
  29  */
  30 
  31 #include <sys/param.h>
  32 #include <sys/types.h>
  33 #include <sys/pathname.h>
  34 #include <sys/errno.h>
  35 #include <sys/cmn_err.h>
  36 #include <sys/debug.h>
  37 #include <sys/systm.h>
  38 #include <sys/unistd.h>
  39 #include <sys/door.h>
  40 #include <sys/socket.h>
  41 #include <nfs/export.h>
  42 #include <nfs/nfs_cmd.h>
  43 #include <sys/kmem.h>
  44 #include <sys/sunddi.h>
  45 
  46 #define NFSCMD_DR_TRYCNT        8
  47 
  48 #ifdef nextdp
  49 #undef nextdp
  50 #endif
  51 #define nextdp(dp)      ((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
  52 
  53 typedef struct nfscmd_globals {
  54         kmutex_t        nfscmd_lock;
  55         door_handle_t   nfscmd_dh;
  56 } nfscmd_globals_t;
  57 
  58 static zone_key_t nfscmd_zone_key;
  59 
  60 static struct charset_cache *nfscmd_charmap(exportinfo_t *exi,
  61     struct sockaddr *sp);
  62 static void *nfscmd_zone_init(zoneid_t);
  63 static void nfscmd_zone_fini(zoneid_t, void *);
  64 
  65 void
  66 nfscmd_args(uint_t did)
  67 {
  68         nfscmd_globals_t *ncg = zone_getspecific(nfscmd_zone_key, curzone);
  69 
  70         mutex_enter(&ncg->nfscmd_lock);
  71         if (ncg->nfscmd_dh != NULL)
  72                 door_ki_rele(ncg->nfscmd_dh);
  73         ncg->nfscmd_dh = door_ki_lookup(did);
  74         mutex_exit(&ncg->nfscmd_lock);
  75 }
  76 
  77 void
  78 nfscmd_init(void)
  79 {
  80         zone_key_create(&nfscmd_zone_key, nfscmd_zone_init,
  81             NULL, nfscmd_zone_fini);
  82 }
  83 
  84 void
  85 nfscmd_fini(void)
  86 {
  87         (void) zone_key_delete(nfscmd_zone_key);
  88 }
  89 
  90 /*ARGSUSED*/
  91 static void *
  92 nfscmd_zone_init(zoneid_t zoneid)
  93 {
  94         nfscmd_globals_t *ncg;
  95 
  96         ncg = kmem_zalloc(sizeof (*ncg), KM_SLEEP);
  97         mutex_init(&ncg->nfscmd_lock, NULL, MUTEX_DEFAULT, NULL);
  98 
  99         return (ncg);
 100 }
 101 
 102 /*ARGSUSED*/
 103 static void
 104 nfscmd_zone_fini(zoneid_t zoneid, void *data)
 105 {
 106         nfscmd_globals_t *ncg = data;
 107 
 108         mutex_destroy(&ncg->nfscmd_lock);
 109         if (ncg->nfscmd_dh)
 110                 door_ki_rele(ncg->nfscmd_dh);
 111         kmem_free(ncg, sizeof (*ncg));
 112 }
 113 
 114 /*
 115  * nfscmd_send(arg, result)
 116  *
 117  * Send a command to the daemon listening on the door. The result is
 118  * returned in the result pointer if the function return value is
 119  * NFSCMD_ERR_SUCCESS. Otherwise it is the error value.
 120  */
 121 int
 122 nfscmd_send(nfscmd_arg_t *arg, nfscmd_res_t *res)
 123 {
 124         door_handle_t   dh;
 125         door_arg_t      da;
 126         door_info_t     di;
 127         int             ntries = 0;
 128         int             last = 0;
 129         nfscmd_globals_t *ncg = zone_getspecific(nfscmd_zone_key, curzone);
 130 
 131 retry:
 132         mutex_enter(&ncg->nfscmd_lock);
 133         dh = ncg->nfscmd_dh;
 134         if (dh != NULL)
 135                 door_ki_hold(dh);
 136         mutex_exit(&ncg->nfscmd_lock);
 137 
 138         if (dh == NULL) {
 139                 /*
 140                  * The rendezvous point has not been established yet !
 141                  * This could mean that either mountd(1m) has not yet
 142                  * been started or that _this_ routine nuked the door
 143                  * handle after receiving an EINTR for a REVOKED door.
 144                  *
 145                  * Returning NFSAUTH_DROP will cause the NFS client
 146                  * to retransmit the request, so let's try to be more
 147                  * rescillient and attempt for ntries before we bail.
 148                  */
 149                 if (++ntries % NFSCMD_DR_TRYCNT) {
 150                         delay(hz);
 151                         goto retry;
 152                 }
 153                 return (NFSCMD_ERR_DROP);
 154         }
 155 
 156         da.data_ptr = (char *)arg;
 
 163         switch (door_ki_upcall(dh, &da)) {
 164         case 0:
 165                 /* Success */
 166                 break;
 167         case EAGAIN:
 168                 /* Need to retry a couple of times */
 169                 door_ki_rele(dh);
 170                 delay(hz);
 171                 goto retry;
 172                 /* NOTREACHED */
 173         case EINTR:
 174                 if (!door_ki_info(dh, &di)) {
 175                         if (di.di_attributes & DOOR_REVOKED) {
 176                                 /*
 177                                  * The server barfed and revoked
 178                                  * the (existing) door on us; we
 179                                  * want to wait to give smf(5) a
 180                                  * chance to restart mountd(1m)
 181                                  * and establish a new door handle.
 182                                  */
 183                                 mutex_enter(&ncg->nfscmd_lock);
 184                                 if (dh == ncg->nfscmd_dh)
 185                                         ncg->nfscmd_dh = NULL;
 186                                 mutex_exit(&ncg->nfscmd_lock);
 187                                 door_ki_rele(dh);
 188                                 delay(hz);
 189                                 goto retry;
 190                         }
 191                         /*
 192                          * If the door was _not_ revoked on us,
 193                          * then more than likely we took an INTR,
 194                          * so we need to fail the operation.
 195                          */
 196                         door_ki_rele(dh);
 197                 }
 198                 /*
 199                  * The only failure that can occur from getting
 200                  * the door info is EINVAL, so we let the code
 201                  * below handle it.
 202                  */
 203                 /* FALLTHROUGH */
 204 
 205         case EBADF:
 206         case EINVAL:
 
 |