qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

nbd/server: introduce NBDExtentArray

Introduce NBDExtentArray class, to handle extents list creation in more
controlled way and with fewer OUT parameters in functions.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Message-id: 20200205112041.6003-9-vsementsov@virtuozzo.com
Signed-off-by: John Snow <jsnow@redhat.com>

authored by

Vladimir Sementsov-Ogievskiy and committed by
John Snow
89cbc7e3 299ea9ff

+118 -92
+118 -92
nbd/server.c
··· 1909 1909 return ret; 1910 1910 } 1911 1911 1912 + typedef struct NBDExtentArray { 1913 + NBDExtent *extents; 1914 + unsigned int nb_alloc; 1915 + unsigned int count; 1916 + uint64_t total_length; 1917 + bool can_add; 1918 + bool converted_to_be; 1919 + } NBDExtentArray; 1920 + 1921 + static NBDExtentArray *nbd_extent_array_new(unsigned int nb_alloc) 1922 + { 1923 + NBDExtentArray *ea = g_new0(NBDExtentArray, 1); 1924 + 1925 + ea->nb_alloc = nb_alloc; 1926 + ea->extents = g_new(NBDExtent, nb_alloc); 1927 + ea->can_add = true; 1928 + 1929 + return ea; 1930 + } 1931 + 1932 + static void nbd_extent_array_free(NBDExtentArray *ea) 1933 + { 1934 + g_free(ea->extents); 1935 + g_free(ea); 1936 + } 1937 + G_DEFINE_AUTOPTR_CLEANUP_FUNC(NBDExtentArray, nbd_extent_array_free); 1938 + 1939 + /* Further modifications of the array after conversion are abandoned */ 1940 + static void nbd_extent_array_convert_to_be(NBDExtentArray *ea) 1941 + { 1942 + int i; 1943 + 1944 + assert(!ea->converted_to_be); 1945 + ea->can_add = false; 1946 + ea->converted_to_be = true; 1947 + 1948 + for (i = 0; i < ea->count; i++) { 1949 + ea->extents[i].flags = cpu_to_be32(ea->extents[i].flags); 1950 + ea->extents[i].length = cpu_to_be32(ea->extents[i].length); 1951 + } 1952 + } 1953 + 1912 1954 /* 1913 - * Populate @extents from block status. Update @bytes to be the actual 1914 - * length encoded (which may be smaller than the original), and update 1915 - * @nb_extents to the number of extents used. 1916 - * 1917 - * Returns zero on success and -errno on bdrv_block_status_above failure. 1955 + * Add extent to NBDExtentArray. If extent can't be added (no available space), 1956 + * return -1. 1957 + * For safety, when returning -1 for the first time, .can_add is set to false, 1958 + * further call to nbd_extent_array_add() will crash. 1959 + * (to avoid the situation, when after failing to add an extent (returned -1), 1960 + * user miss this failure and add another extent, which is successfully added 1961 + * (array is full, but new extent may be squashed into the last one), then we 1962 + * have invalid array with skipped extent) 1918 1963 */ 1919 - static int blockstatus_to_extents(BlockDriverState *bs, uint64_t offset, 1920 - uint64_t *bytes, NBDExtent *extents, 1921 - unsigned int *nb_extents) 1964 + static int nbd_extent_array_add(NBDExtentArray *ea, 1965 + uint32_t length, uint32_t flags) 1922 1966 { 1923 - uint64_t remaining_bytes = *bytes; 1924 - NBDExtent *extent = extents, *extents_end = extents + *nb_extents; 1925 - bool first_extent = true; 1967 + assert(ea->can_add); 1926 1968 1927 - assert(*nb_extents); 1928 - while (remaining_bytes) { 1969 + if (!length) { 1970 + return 0; 1971 + } 1972 + 1973 + /* Extend previous extent if flags are the same */ 1974 + if (ea->count > 0 && flags == ea->extents[ea->count - 1].flags) { 1975 + uint64_t sum = (uint64_t)length + ea->extents[ea->count - 1].length; 1976 + 1977 + if (sum <= UINT32_MAX) { 1978 + ea->extents[ea->count - 1].length = sum; 1979 + ea->total_length += length; 1980 + return 0; 1981 + } 1982 + } 1983 + 1984 + if (ea->count >= ea->nb_alloc) { 1985 + ea->can_add = false; 1986 + return -1; 1987 + } 1988 + 1989 + ea->total_length += length; 1990 + ea->extents[ea->count] = (NBDExtent) {.length = length, .flags = flags}; 1991 + ea->count++; 1992 + 1993 + return 0; 1994 + } 1995 + 1996 + static int blockstatus_to_extents(BlockDriverState *bs, uint64_t offset, 1997 + uint64_t bytes, NBDExtentArray *ea) 1998 + { 1999 + while (bytes) { 1929 2000 uint32_t flags; 1930 2001 int64_t num; 1931 - int ret = bdrv_block_status_above(bs, NULL, offset, remaining_bytes, 1932 - &num, NULL, NULL); 2002 + int ret = bdrv_block_status_above(bs, NULL, offset, bytes, &num, 2003 + NULL, NULL); 1933 2004 1934 2005 if (ret < 0) { 1935 2006 return ret; ··· 1938 2009 flags = (ret & BDRV_BLOCK_ALLOCATED ? 0 : NBD_STATE_HOLE) | 1939 2010 (ret & BDRV_BLOCK_ZERO ? NBD_STATE_ZERO : 0); 1940 2011 1941 - if (first_extent) { 1942 - extent->flags = flags; 1943 - extent->length = num; 1944 - first_extent = false; 1945 - } else if (flags == extent->flags) { 1946 - /* extend current extent */ 1947 - extent->length += num; 1948 - } else { 1949 - if (extent + 1 == extents_end) { 1950 - break; 1951 - } 2012 + if (nbd_extent_array_add(ea, num, flags) < 0) { 2013 + return 0; 2014 + } 1952 2015 1953 - /* start new extent */ 1954 - extent++; 1955 - extent->flags = flags; 1956 - extent->length = num; 1957 - } 1958 2016 offset += num; 1959 - remaining_bytes -= num; 2017 + bytes -= num; 1960 2018 } 1961 - 1962 - extents_end = extent + 1; 1963 - 1964 - for (extent = extents; extent < extents_end; extent++) { 1965 - extent->flags = cpu_to_be32(extent->flags); 1966 - extent->length = cpu_to_be32(extent->length); 1967 - } 1968 - 1969 - *bytes -= remaining_bytes; 1970 - *nb_extents = extents_end - extents; 1971 2019 1972 2020 return 0; 1973 2021 } 1974 2022 1975 - /* nbd_co_send_extents 2023 + /* 2024 + * nbd_co_send_extents 1976 2025 * 1977 - * @length is only for tracing purposes (and may be smaller or larger 1978 - * than the client's original request). @last controls whether 1979 - * NBD_REPLY_FLAG_DONE is sent. @extents should already be in 1980 - * big-endian format. 2026 + * @ea is converted to BE by the function 2027 + * @last controls whether NBD_REPLY_FLAG_DONE is sent. 1981 2028 */ 1982 2029 static int nbd_co_send_extents(NBDClient *client, uint64_t handle, 1983 - NBDExtent *extents, unsigned int nb_extents, 1984 - uint64_t length, bool last, 1985 - uint32_t context_id, Error **errp) 2030 + NBDExtentArray *ea, 2031 + bool last, uint32_t context_id, Error **errp) 1986 2032 { 1987 2033 NBDStructuredMeta chunk; 1988 - 1989 2034 struct iovec iov[] = { 1990 2035 {.iov_base = &chunk, .iov_len = sizeof(chunk)}, 1991 - {.iov_base = extents, .iov_len = nb_extents * sizeof(extents[0])} 2036 + {.iov_base = ea->extents, .iov_len = ea->count * sizeof(ea->extents[0])} 1992 2037 }; 1993 2038 1994 - trace_nbd_co_send_extents(handle, nb_extents, context_id, length, last); 2039 + nbd_extent_array_convert_to_be(ea); 2040 + 2041 + trace_nbd_co_send_extents(handle, ea->count, context_id, ea->total_length, 2042 + last); 1995 2043 set_be_chunk(&chunk.h, last ? NBD_REPLY_FLAG_DONE : 0, 1996 2044 NBD_REPLY_TYPE_BLOCK_STATUS, 1997 2045 handle, sizeof(chunk) - sizeof(chunk.h) + iov[1].iov_len); ··· 2009 2057 { 2010 2058 int ret; 2011 2059 unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BLOCK_STATUS_EXTENTS; 2012 - NBDExtent *extents = g_new(NBDExtent, nb_extents); 2013 - uint64_t final_length = length; 2060 + g_autoptr(NBDExtentArray) ea = nbd_extent_array_new(nb_extents); 2014 2061 2015 - ret = blockstatus_to_extents(bs, offset, &final_length, extents, 2016 - &nb_extents); 2062 + ret = blockstatus_to_extents(bs, offset, length, ea); 2017 2063 if (ret < 0) { 2018 - g_free(extents); 2019 2064 return nbd_co_send_structured_error( 2020 2065 client, handle, -ret, "can't get block status", errp); 2021 2066 } 2022 2067 2023 - ret = nbd_co_send_extents(client, handle, extents, nb_extents, 2024 - final_length, last, context_id, errp); 2025 - 2026 - g_free(extents); 2027 - 2028 - return ret; 2068 + return nbd_co_send_extents(client, handle, ea, last, context_id, errp); 2029 2069 } 2030 2070 2031 2071 /* 2032 - * Populate @extents from a dirty bitmap. Unless @dont_fragment, the 2033 - * final extent may exceed the original @length. Store in @length the 2034 - * byte length encoded (which may be smaller or larger than the 2035 - * original), and return the number of extents used. 2072 + * Populate @ea from a dirty bitmap. Unless @dont_fragment, the 2073 + * final extent may exceed the original @length. 2036 2074 */ 2037 - static unsigned int bitmap_to_extents(BdrvDirtyBitmap *bitmap, uint64_t offset, 2038 - uint64_t *length, NBDExtent *extents, 2039 - unsigned int nb_extents, 2040 - bool dont_fragment) 2075 + static void bitmap_to_extents(BdrvDirtyBitmap *bitmap, 2076 + uint64_t offset, uint64_t length, 2077 + NBDExtentArray *ea, bool dont_fragment) 2041 2078 { 2042 2079 uint64_t begin = offset, end = offset; 2043 - uint64_t overall_end = offset + *length; 2044 - unsigned int i = 0; 2080 + uint64_t overall_end = offset + length; 2045 2081 BdrvDirtyBitmapIter *it; 2046 2082 bool dirty; 2047 2083 ··· 2050 2086 it = bdrv_dirty_iter_new(bitmap); 2051 2087 dirty = bdrv_dirty_bitmap_get_locked(bitmap, offset); 2052 2088 2053 - assert(begin < overall_end && nb_extents); 2054 - while (begin < overall_end && i < nb_extents) { 2089 + while (begin < overall_end) { 2055 2090 bool next_dirty = !dirty; 2056 2091 2057 2092 if (dirty) { ··· 2071 2106 end = overall_end; 2072 2107 } 2073 2108 2074 - extents[i].length = cpu_to_be32(end - begin); 2075 - extents[i].flags = cpu_to_be32(dirty ? NBD_STATE_DIRTY : 0); 2076 - i++; 2109 + if (nbd_extent_array_add(ea, end - begin, 2110 + dirty ? NBD_STATE_DIRTY : 0) < 0) { 2111 + break; 2112 + } 2077 2113 begin = end; 2078 2114 dirty = next_dirty; 2079 2115 } ··· 2083 2119 bdrv_dirty_bitmap_unlock(bitmap); 2084 2120 2085 2121 assert(offset < end); 2086 - *length = end - offset; 2087 - return i; 2088 2122 } 2089 2123 2090 2124 static int nbd_co_send_bitmap(NBDClient *client, uint64_t handle, ··· 2092 2126 uint32_t length, bool dont_fragment, bool last, 2093 2127 uint32_t context_id, Error **errp) 2094 2128 { 2095 - int ret; 2096 2129 unsigned int nb_extents = dont_fragment ? 1 : NBD_MAX_BLOCK_STATUS_EXTENTS; 2097 - NBDExtent *extents = g_new(NBDExtent, nb_extents); 2098 - uint64_t final_length = length; 2130 + g_autoptr(NBDExtentArray) ea = nbd_extent_array_new(nb_extents); 2099 2131 2100 - nb_extents = bitmap_to_extents(bitmap, offset, &final_length, extents, 2101 - nb_extents, dont_fragment); 2132 + bitmap_to_extents(bitmap, offset, length, ea, dont_fragment); 2102 2133 2103 - ret = nbd_co_send_extents(client, handle, extents, nb_extents, 2104 - final_length, last, context_id, errp); 2105 - 2106 - g_free(extents); 2107 - 2108 - return ret; 2134 + return nbd_co_send_extents(client, handle, ea, last, context_id, errp); 2109 2135 } 2110 2136 2111 2137 /* nbd_co_receive_request