Print this page
11928 rpcmod's clnt_cots can do zero-length kmem allocations


   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 2016 Nexenta Systems, Inc.  All rights reserved.
  24  * Copyright (c) 2016 by Delphix. All rights reserved.

  25  */
  26 
  27 /*
  28  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  29  * Use is subject to license terms.
  30  */
  31 
  32 /*
  33  * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
  34  *              All Rights Reserved
  35  */
  36 
  37 /*
  38  * Portions of this source code were derived from Berkeley 4.3 BSD
  39  * under license from the Regents of the University of California.
  40  */
  41 
  42 
  43 /*
  44  * Implements a kernel based, client side RPC over Connection Oriented


1919                         RPCLOG(8, "connmgr_get: too many conns, dooming entry"
1920                             " %p\n", (void *)lru_entry->x_tiptr);
1921                         lru_entry->x_doomed = TRUE;
1922                         goto use_new_conn;
1923                 }
1924 
1925                 /*
1926                  * If we are at the maximum number of connections to
1927                  * the server, hand back the least recently used one.
1928                  */
1929                 if (i == clnt_max_conns) {
1930                         /*
1931                          * Copy into the handle the source address of
1932                          * the connection, which we will use in case of
1933                          * a later retry.
1934                          */
1935                         if (srcaddr->len != lru_entry->x_src.len) {
1936                                 if (srcaddr->len > 0)
1937                                         kmem_free(srcaddr->buf,
1938                                             srcaddr->maxlen);
1939                                 srcaddr->buf = kmem_zalloc(

1940                                     lru_entry->x_src.len, KM_SLEEP);
1941                                 srcaddr->maxlen = srcaddr->len =
1942                                     lru_entry->x_src.len;
1943                         }
1944                         bcopy(lru_entry->x_src.buf, srcaddr->buf, srcaddr->len);
1945                         RPCLOG(2, "connmgr_get: call going out on %p\n",
1946                             (void *)lru_entry);
1947                         lru_entry->x_time = ddi_get_lbolt();
1948                         CONN_HOLD(lru_entry);
1949 
1950                         if ((i > 1) && (prev != &cm_hd)) {
1951                                 /*
1952                                  * remove and re-insert entry at head of list.
1953                                  */
1954                                 *prev = lru_entry->x_next;
1955                                 lru_entry->x_next = cm_hd;
1956                                 cm_hd = lru_entry;
1957                         }
1958 
1959                         mutex_exit(&connmgr_lock);


2074 
2075                 /*
2076                  * We cannot find an entry in the list for this retry.
2077                  * Either the entry has been removed temporarily to be
2078                  * reconnected by another thread, or the original call
2079                  * got a port but never got connected,
2080                  * and hence the transport never got put in the
2081                  * list.  Fall through to the "create new connection" code -
2082                  * the former case will fail there trying to rebind the port,
2083                  * and the later case (and any other pathological cases) will
2084                  * rebind and reconnect and not hang the client machine.
2085                  */
2086                 RPCLOG0(8, "connmgr_get: no entry in list for retry\n");
2087         }
2088         /*
2089          * Set up a transport entry in the connection manager's list.
2090          */
2091         cm_entry = (struct cm_xprt *)
2092             kmem_zalloc(sizeof (struct cm_xprt), KM_SLEEP);
2093 
2094         cm_entry->x_server.buf = kmem_zalloc(destaddr->len, KM_SLEEP);
2095         bcopy(destaddr->buf, cm_entry->x_server.buf, destaddr->len);
2096         cm_entry->x_server.len = cm_entry->x_server.maxlen = destaddr->len;
2097 
2098         cm_entry->x_state_flags = X_THREAD;
2099         cm_entry->x_ref = 1;
2100         cm_entry->x_family = addrfmly;
2101         cm_entry->x_rdev = device;
2102         cm_entry->x_zoneid = zoneid;
2103         mutex_init(&cm_entry->x_lock, NULL, MUTEX_DEFAULT, NULL);
2104         cv_init(&cm_entry->x_cv, NULL, CV_DEFAULT, NULL);
2105         cv_init(&cm_entry->x_conn_cv, NULL, CV_DEFAULT, NULL);
2106         cv_init(&cm_entry->x_dis_cv, NULL, CV_DEFAULT, NULL);
2107 
2108         /*
2109          * Note that we add this partially initialized entry to the
2110          * connection list. This is so that we don't have connections to
2111          * the same server.
2112          *
2113          * Note that x_src is not initialized at this point. This is because
2114          * retryaddr might be NULL in which case x_src is whatever


2239                 calllist_t call;
2240 
2241                 bzero(&call, sizeof (call));
2242                 cv_init(&call.call_cv, NULL, CV_DEFAULT, NULL);
2243 
2244                 /*
2245                  * This is a bound end-point so don't close it's stream.
2246                  */
2247                 connected = connmgr_connect(cm_entry, wq, destaddr, addrfmly,
2248                     &call, &tidu_size, FALSE, waitp, nosignal, cr);
2249                 *rpcerr = call.call_err;
2250                 cv_destroy(&call.call_cv);
2251 
2252         }
2253 
2254         mutex_enter(&connmgr_lock);
2255 
2256         /*
2257          * Set up a transport entry in the connection manager's list.
2258          */
2259         cm_entry->x_src.buf = kmem_zalloc(srcaddr->len, KM_SLEEP);

2260         bcopy(srcaddr->buf, cm_entry->x_src.buf, srcaddr->len);
2261         cm_entry->x_src.len = cm_entry->x_src.maxlen = srcaddr->len;

2262 
2263         cm_entry->x_tiptr = tiptr;
2264         cm_entry->x_time = ddi_get_lbolt();
2265 
2266         if (tiptr->tp_info.servtype == T_COTS_ORD)
2267                 cm_entry->x_ordrel = TRUE;
2268         else
2269                 cm_entry->x_ordrel = FALSE;
2270 
2271         cm_entry->x_tidu_size = tidu_size;
2272 
2273         if (cm_entry->x_early_disc) {
2274                 /*
2275                  * We need to check if a disconnect request has come
2276                  * while we are connected, if so, then we need to
2277                  * set rpcerr->re_status appropriately before returning
2278                  * NULL to caller.
2279                  */
2280                 if (rpcerr->re_status == RPC_SUCCESS)
2281                         rpcerr->re_status = RPC_XPRTFAILED;


2423 
2424                 cv_broadcast(&cm_entry->x_conn_cv);
2425 
2426                 if (cm_entry->x_connected == FALSE) {
2427                         mutex_exit(&connmgr_lock);
2428                         connmgr_release(cm_entry);
2429                         return (NULL);
2430                 }
2431         }
2432 
2433         if (srcaddr != NULL) {
2434                 /*
2435                  * Copy into the handle the
2436                  * source address of the
2437                  * connection, which we will use
2438                  * in case of a later retry.
2439                  */
2440                 if (srcaddr->len != cm_entry->x_src.len) {
2441                         if (srcaddr->maxlen > 0)
2442                                 kmem_free(srcaddr->buf, srcaddr->maxlen);
2443                         srcaddr->buf = kmem_zalloc(cm_entry->x_src.len,

2444                             KM_SLEEP);
2445                         srcaddr->maxlen = srcaddr->len =
2446                             cm_entry->x_src.len;
2447                 }
2448                 bcopy(cm_entry->x_src.buf, srcaddr->buf, srcaddr->len);
2449         }
2450         cm_entry->x_time = ddi_get_lbolt();
2451         mutex_exit(&connmgr_lock);
2452         return (cm_entry);
2453 }
2454 
2455 /*
2456  * If we need to send a T_DISCON_REQ, send one.
2457  */
2458 static void
2459 connmgr_dis_and_wait(struct cm_xprt *cm_entry)
2460 {
2461         ASSERT(MUTEX_HELD(&connmgr_lock));
2462         for (;;) {
2463                 while (cm_entry->x_needdis == TRUE) {
2464                         RPCLOG(8, "connmgr_dis_and_wait: need "
2465                             "T_DISCON_REQ for connection 0x%p\n",
2466                             (void *)cm_entry);




   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 2016 Nexenta Systems, Inc.  All rights reserved.
  24  * Copyright (c) 2016 by Delphix. All rights reserved.
  25  * Copyright 2019 Joyent, Inc.
  26  */
  27 
  28 /*
  29  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  30  * Use is subject to license terms.
  31  */
  32 
  33 /*
  34  * Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T
  35  *              All Rights Reserved
  36  */
  37 
  38 /*
  39  * Portions of this source code were derived from Berkeley 4.3 BSD
  40  * under license from the Regents of the University of California.
  41  */
  42 
  43 
  44 /*
  45  * Implements a kernel based, client side RPC over Connection Oriented


1920                         RPCLOG(8, "connmgr_get: too many conns, dooming entry"
1921                             " %p\n", (void *)lru_entry->x_tiptr);
1922                         lru_entry->x_doomed = TRUE;
1923                         goto use_new_conn;
1924                 }
1925 
1926                 /*
1927                  * If we are at the maximum number of connections to
1928                  * the server, hand back the least recently used one.
1929                  */
1930                 if (i == clnt_max_conns) {
1931                         /*
1932                          * Copy into the handle the source address of
1933                          * the connection, which we will use in case of
1934                          * a later retry.
1935                          */
1936                         if (srcaddr->len != lru_entry->x_src.len) {
1937                                 if (srcaddr->len > 0)
1938                                         kmem_free(srcaddr->buf,
1939                                             srcaddr->maxlen);
1940                                 ASSERT(lru_entry->x_src.len != 0);
1941                                 srcaddr->buf = kmem_alloc(
1942                                     lru_entry->x_src.len, KM_SLEEP);
1943                                 srcaddr->maxlen = srcaddr->len =
1944                                     lru_entry->x_src.len;
1945                         }
1946                         bcopy(lru_entry->x_src.buf, srcaddr->buf, srcaddr->len);
1947                         RPCLOG(2, "connmgr_get: call going out on %p\n",
1948                             (void *)lru_entry);
1949                         lru_entry->x_time = ddi_get_lbolt();
1950                         CONN_HOLD(lru_entry);
1951 
1952                         if ((i > 1) && (prev != &cm_hd)) {
1953                                 /*
1954                                  * remove and re-insert entry at head of list.
1955                                  */
1956                                 *prev = lru_entry->x_next;
1957                                 lru_entry->x_next = cm_hd;
1958                                 cm_hd = lru_entry;
1959                         }
1960 
1961                         mutex_exit(&connmgr_lock);


2076 
2077                 /*
2078                  * We cannot find an entry in the list for this retry.
2079                  * Either the entry has been removed temporarily to be
2080                  * reconnected by another thread, or the original call
2081                  * got a port but never got connected,
2082                  * and hence the transport never got put in the
2083                  * list.  Fall through to the "create new connection" code -
2084                  * the former case will fail there trying to rebind the port,
2085                  * and the later case (and any other pathological cases) will
2086                  * rebind and reconnect and not hang the client machine.
2087                  */
2088                 RPCLOG0(8, "connmgr_get: no entry in list for retry\n");
2089         }
2090         /*
2091          * Set up a transport entry in the connection manager's list.
2092          */
2093         cm_entry = (struct cm_xprt *)
2094             kmem_zalloc(sizeof (struct cm_xprt), KM_SLEEP);
2095 
2096         cm_entry->x_server.buf = kmem_alloc(destaddr->len, KM_SLEEP);
2097         bcopy(destaddr->buf, cm_entry->x_server.buf, destaddr->len);
2098         cm_entry->x_server.len = cm_entry->x_server.maxlen = destaddr->len;
2099 
2100         cm_entry->x_state_flags = X_THREAD;
2101         cm_entry->x_ref = 1;
2102         cm_entry->x_family = addrfmly;
2103         cm_entry->x_rdev = device;
2104         cm_entry->x_zoneid = zoneid;
2105         mutex_init(&cm_entry->x_lock, NULL, MUTEX_DEFAULT, NULL);
2106         cv_init(&cm_entry->x_cv, NULL, CV_DEFAULT, NULL);
2107         cv_init(&cm_entry->x_conn_cv, NULL, CV_DEFAULT, NULL);
2108         cv_init(&cm_entry->x_dis_cv, NULL, CV_DEFAULT, NULL);
2109 
2110         /*
2111          * Note that we add this partially initialized entry to the
2112          * connection list. This is so that we don't have connections to
2113          * the same server.
2114          *
2115          * Note that x_src is not initialized at this point. This is because
2116          * retryaddr might be NULL in which case x_src is whatever


2241                 calllist_t call;
2242 
2243                 bzero(&call, sizeof (call));
2244                 cv_init(&call.call_cv, NULL, CV_DEFAULT, NULL);
2245 
2246                 /*
2247                  * This is a bound end-point so don't close it's stream.
2248                  */
2249                 connected = connmgr_connect(cm_entry, wq, destaddr, addrfmly,
2250                     &call, &tidu_size, FALSE, waitp, nosignal, cr);
2251                 *rpcerr = call.call_err;
2252                 cv_destroy(&call.call_cv);
2253 
2254         }
2255 
2256         mutex_enter(&connmgr_lock);
2257 
2258         /*
2259          * Set up a transport entry in the connection manager's list.
2260          */
2261         if (srcaddr->len > 0) {
2262                 cm_entry->x_src.buf = kmem_alloc(srcaddr->len, KM_SLEEP);
2263                 bcopy(srcaddr->buf, cm_entry->x_src.buf, srcaddr->len);
2264                 cm_entry->x_src.len = cm_entry->x_src.maxlen = srcaddr->len;
2265         } /* Else kmem_zalloc() of cm_entry already sets its x_src to NULL. */
2266 
2267         cm_entry->x_tiptr = tiptr;
2268         cm_entry->x_time = ddi_get_lbolt();
2269 
2270         if (tiptr->tp_info.servtype == T_COTS_ORD)
2271                 cm_entry->x_ordrel = TRUE;
2272         else
2273                 cm_entry->x_ordrel = FALSE;
2274 
2275         cm_entry->x_tidu_size = tidu_size;
2276 
2277         if (cm_entry->x_early_disc) {
2278                 /*
2279                  * We need to check if a disconnect request has come
2280                  * while we are connected, if so, then we need to
2281                  * set rpcerr->re_status appropriately before returning
2282                  * NULL to caller.
2283                  */
2284                 if (rpcerr->re_status == RPC_SUCCESS)
2285                         rpcerr->re_status = RPC_XPRTFAILED;


2427 
2428                 cv_broadcast(&cm_entry->x_conn_cv);
2429 
2430                 if (cm_entry->x_connected == FALSE) {
2431                         mutex_exit(&connmgr_lock);
2432                         connmgr_release(cm_entry);
2433                         return (NULL);
2434                 }
2435         }
2436 
2437         if (srcaddr != NULL) {
2438                 /*
2439                  * Copy into the handle the
2440                  * source address of the
2441                  * connection, which we will use
2442                  * in case of a later retry.
2443                  */
2444                 if (srcaddr->len != cm_entry->x_src.len) {
2445                         if (srcaddr->maxlen > 0)
2446                                 kmem_free(srcaddr->buf, srcaddr->maxlen);
2447                         ASSERT(cm_entry->x_src.len != 0);
2448                         srcaddr->buf = kmem_alloc(cm_entry->x_src.len,
2449                             KM_SLEEP);
2450                         srcaddr->maxlen = srcaddr->len = cm_entry->x_src.len;

2451                 }
2452                 bcopy(cm_entry->x_src.buf, srcaddr->buf, srcaddr->len);
2453         }
2454         cm_entry->x_time = ddi_get_lbolt();
2455         mutex_exit(&connmgr_lock);
2456         return (cm_entry);
2457 }
2458 
2459 /*
2460  * If we need to send a T_DISCON_REQ, send one.
2461  */
2462 static void
2463 connmgr_dis_and_wait(struct cm_xprt *cm_entry)
2464 {
2465         ASSERT(MUTEX_HELD(&connmgr_lock));
2466         for (;;) {
2467                 while (cm_entry->x_needdis == TRUE) {
2468                         RPCLOG(8, "connmgr_dis_and_wait: need "
2469                             "T_DISCON_REQ for connection 0x%p\n",
2470                             (void *)cm_entry);