Add -p switch to "zpool get"
[zfs.git] / module / zfs / zap_leaf.c
index da498b6..ad21882 100644 (file)
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident  "%Z%%M% %I%     %E% SMI"
-
 /*
  * The 512-byte leaf is broken into 32 16-byte chunks.
  * chunk number n means l_chunk[n], even though the header precedes it.
  * the names are stored null-terminated.
  */
 
+#include <sys/zio.h>
+#include <sys/spa.h>
+#include <sys/dmu.h>
 #include <sys/zfs_context.h>
+#include <sys/fs/zfs.h>
 #include <sys/zap.h>
 #include <sys/zap_impl.h>
 #include <sys/zap_leaf.h>
-#include <sys/spa.h>
-#include <sys/dmu.h>
+#include <sys/arc.h>
 
 static uint16_t *zap_leaf_rehash_entry(zap_leaf_t *l, uint16_t entry);
 
@@ -127,12 +127,12 @@ zap_leaf_byteswap(zap_leaf_phys_t *buf, int size)
                        le = &lc->l_entry;
 
                        le->le_type =           BSWAP_8(le->le_type);
-                       le->le_int_size =       BSWAP_8(le->le_int_size);
+                       le->le_value_intlen =   BSWAP_8(le->le_value_intlen);
                        le->le_next =           BSWAP_16(le->le_next);
                        le->le_name_chunk =     BSWAP_16(le->le_name_chunk);
-                       le->le_name_length =    BSWAP_16(le->le_name_length);
+                       le->le_name_numints =   BSWAP_16(le->le_name_numints);
                        le->le_value_chunk =    BSWAP_16(le->le_value_chunk);
-                       le->le_value_length =   BSWAP_16(le->le_value_length);
+                       le->le_value_numints =  BSWAP_16(le->le_value_numints);
                        le->le_cd =             BSWAP_32(le->le_cd);
                        le->le_hash =           BSWAP_64(le->le_hash);
                        break;
@@ -215,12 +215,12 @@ zap_leaf_chunk_free(zap_leaf_t *l, uint16_t chunk)
 
 static uint16_t
 zap_leaf_array_create(zap_leaf_t *l, const char *buf,
-       int integer_size, int num_integers)
+    int integer_size, int num_integers)
 {
        uint16_t chunk_head;
        uint16_t *chunkp = &chunk_head;
        int byten = 0;
-       uint64_t value;
+       uint64_t value = 0;
        int shift = (integer_size-1)*8;
        int len = num_integers;
 
@@ -273,11 +273,12 @@ zap_leaf_array_free(zap_leaf_t *l, uint16_t *chunkp)
 static void
 zap_leaf_array_read(zap_leaf_t *l, uint16_t chunk,
     int array_int_len, int array_len, int buf_int_len, uint64_t buf_len,
-    char *buf)
+    void *buf)
 {
        int len = MIN(array_len, buf_len);
        int byten = 0;
        uint64_t value = 0;
+       char *p = buf;
 
        ASSERT3U(array_int_len, <=, buf_int_len);
 
@@ -285,7 +286,7 @@ zap_leaf_array_read(zap_leaf_t *l, uint16_t chunk,
        if (array_int_len == 8 && buf_int_len == 8 && len == 1) {
                struct zap_leaf_array *la = &ZAP_LEAF_CHUNK(l, chunk).l_array;
                uint8_t *ip = la->la_array;
-               uint64_t *buf64 = (uint64_t *)buf;
+               uint64_t *buf64 = buf;
 
                *buf64 = (uint64_t)ip[0] << 56 | (uint64_t)ip[1] << 48 |
                    (uint64_t)ip[2] << 40 | (uint64_t)ip[3] << 32 |
@@ -300,8 +301,8 @@ zap_leaf_array_read(zap_leaf_t *l, uint16_t chunk,
                while (chunk != CHAIN_END) {
                        struct zap_leaf_array *la =
                            &ZAP_LEAF_CHUNK(l, chunk).l_array;
-                       bcopy(la->la_array, buf, ZAP_LEAF_ARRAY_BYTES);
-                       buf += ZAP_LEAF_ARRAY_BYTES;
+                       bcopy(la->la_array, p, ZAP_LEAF_ARRAY_BYTES);
+                       p += ZAP_LEAF_ARRAY_BYTES;
                        chunk = la->la_next;
                }
                return;
@@ -316,50 +317,69 @@ zap_leaf_array_read(zap_leaf_t *l, uint16_t chunk,
                        value = (value << 8) | la->la_array[i];
                        byten++;
                        if (byten == array_int_len) {
-                               stv(buf_int_len, buf, value);
+                               stv(buf_int_len, p, value);
                                byten = 0;
                                len--;
                                if (len == 0)
                                        return;
-                               buf += buf_int_len;
+                               p += buf_int_len;
                        }
                }
                chunk = la->la_next;
        }
 }
 
-/*
- * Only to be used on 8-bit arrays.
- * array_len is actual len in bytes (not encoded le_value_length).
- * namenorm is null-terminated.
- */
 static boolean_t
-zap_leaf_array_match(zap_leaf_t *l, zap_name_t *zn, int chunk, int array_len)
+zap_leaf_array_match(zap_leaf_t *l, zap_name_t *zn,
+    int chunk, int array_numints)
 {
        int bseen = 0;
 
+       if (zap_getflags(zn->zn_zap) & ZAP_FLAG_UINT64_KEY) {
+               uint64_t *thiskey;
+               boolean_t match;
+
+               ASSERT(zn->zn_key_intlen == sizeof (*thiskey));
+               thiskey = kmem_alloc(array_numints * sizeof (*thiskey),
+                   KM_PUSHPAGE);
+
+               zap_leaf_array_read(l, chunk, sizeof (*thiskey), array_numints,
+                   sizeof (*thiskey), array_numints, thiskey);
+               match = bcmp(thiskey, zn->zn_key_orig,
+                   array_numints * sizeof (*thiskey)) == 0;
+               kmem_free(thiskey, array_numints * sizeof (*thiskey));
+               return (match);
+       }
+
+       ASSERT(zn->zn_key_intlen == 1);
        if (zn->zn_matchtype == MT_FIRST) {
-               char *thisname = kmem_alloc(array_len, KM_SLEEP);
+               char *thisname = kmem_alloc(array_numints, KM_PUSHPAGE);
                boolean_t match;
 
-               zap_leaf_array_read(l, chunk, 1, array_len, 1,
-                   array_len, thisname);
+               zap_leaf_array_read(l, chunk, sizeof (char), array_numints,
+                   sizeof (char), array_numints, thisname);
                match = zap_match(zn, thisname);
-               kmem_free(thisname, array_len);
+               kmem_free(thisname, array_numints);
                return (match);
        }
 
-       /* Fast path for exact matching */
-       while (bseen < array_len) {
+       /*
+        * Fast path for exact matching.
+        * First check that the lengths match, so that we don't read
+        * past the end of the zn_key_orig array.
+        */
+       if (array_numints != zn->zn_key_orig_numints)
+               return (B_FALSE);
+       while (bseen < array_numints) {
                struct zap_leaf_array *la = &ZAP_LEAF_CHUNK(l, chunk).l_array;
-               int toread = MIN(array_len - bseen, ZAP_LEAF_ARRAY_BYTES);
+               int toread = MIN(array_numints - bseen, ZAP_LEAF_ARRAY_BYTES);
                ASSERT3U(chunk, <, ZAP_LEAF_NUMCHUNKS(l));
-               if (bcmp(la->la_array, zn->zn_name_orij + bseen, toread))
+               if (bcmp(la->la_array, (char *)zn->zn_key_orig + bseen, toread))
                        break;
                chunk = la->la_next;
                bseen += toread;
        }
-       return (bseen == array_len);
+       return (bseen == array_numints);
 }
 
 /*
@@ -394,9 +414,9 @@ again:
                ASSERT(zn->zn_matchtype == MT_EXACT ||
                    (l->l_phys->l_hdr.lh_flags & ZLF_ENTRIES_CDSORTED));
                if (zap_leaf_array_match(l, zn, le->le_name_chunk,
-                   le->le_name_length)) {
-                       zeh->zeh_num_integers = le->le_value_length;
-                       zeh->zeh_integer_size = le->le_int_size;
+                   le->le_name_numints)) {
+                       zeh->zeh_num_integers = le->le_value_numints;
+                       zeh->zeh_integer_size = le->le_value_intlen;
                        zeh->zeh_cd = le->le_cd;
                        zeh->zeh_hash = le->le_hash;
                        zeh->zeh_chunkp = chunkp;
@@ -427,7 +447,7 @@ zap_leaf_lookup_closest(zap_leaf_t *l,
 {
        uint16_t chunk;
        uint64_t besth = -1ULL;
-       uint32_t bestcd = ZAP_MAXCD;
+       uint32_t bestcd = -1U;
        uint16_t bestlh = ZAP_LEAF_HASH_NUMENTRIES(l)-1;
        uint16_t lh;
        struct zap_leaf_entry *le;
@@ -449,8 +469,8 @@ zap_leaf_lookup_closest(zap_leaf_t *l,
                                besth = le->le_hash;
                                bestcd = le->le_cd;
 
-                               zeh->zeh_num_integers = le->le_value_length;
-                               zeh->zeh_integer_size = le->le_int_size;
+                               zeh->zeh_num_integers = le->le_value_numints;
+                               zeh->zeh_integer_size = le->le_value_intlen;
                                zeh->zeh_cd = le->le_cd;
                                zeh->zeh_hash = le->le_hash;
                                zeh->zeh_fakechunk = chunk;
@@ -460,7 +480,7 @@ zap_leaf_lookup_closest(zap_leaf_t *l,
                }
        }
 
-       return (bestcd == ZAP_MAXCD ? ENOENT : 0);
+       return (bestcd == -1U ? ENOENT : 0);
 }
 
 int
@@ -471,11 +491,12 @@ zap_entry_read(const zap_entry_handle_t *zeh,
            ZAP_LEAF_ENTRY(zeh->zeh_leaf, *zeh->zeh_chunkp);
        ASSERT3U(le->le_type, ==, ZAP_CHUNK_ENTRY);
 
-       if (le->le_int_size > integer_size)
+       if (le->le_value_intlen > integer_size)
                return (EINVAL);
 
-       zap_leaf_array_read(zeh->zeh_leaf, le->le_value_chunk, le->le_int_size,
-           le->le_value_length, integer_size, num_integers, buf);
+       zap_leaf_array_read(zeh->zeh_leaf, le->le_value_chunk,
+           le->le_value_intlen, le->le_value_numints,
+           integer_size, num_integers, buf);
 
        if (zeh->zeh_num_integers > num_integers)
                return (EOVERFLOW);
@@ -484,15 +505,21 @@ zap_entry_read(const zap_entry_handle_t *zeh,
 }
 
 int
-zap_entry_read_name(const zap_entry_handle_t *zeh, uint16_t buflen, char *buf)
+zap_entry_read_name(zap_t *zap, const zap_entry_handle_t *zeh, uint16_t buflen,
+    char *buf)
 {
        struct zap_leaf_entry *le =
            ZAP_LEAF_ENTRY(zeh->zeh_leaf, *zeh->zeh_chunkp);
        ASSERT3U(le->le_type, ==, ZAP_CHUNK_ENTRY);
 
-       zap_leaf_array_read(zeh->zeh_leaf, le->le_name_chunk, 1,
-           le->le_name_length, 1, buflen, buf);
-       if (le->le_name_length > buflen)
+       if (zap_getflags(zap) & ZAP_FLAG_UINT64_KEY) {
+               zap_leaf_array_read(zeh->zeh_leaf, le->le_name_chunk, 8,
+                   le->le_name_numints, 8, buflen / 8, buf);
+       } else {
+               zap_leaf_array_read(zeh->zeh_leaf, le->le_name_chunk, 1,
+                   le->le_name_numints, 1, buflen, buf);
+       }
+       if (le->le_name_numints > buflen)
                return (EOVERFLOW);
        return (0);
 }
@@ -506,24 +533,16 @@ zap_entry_update(zap_entry_handle_t *zeh,
        struct zap_leaf_entry *le = ZAP_LEAF_ENTRY(l, *zeh->zeh_chunkp);
 
        delta_chunks = ZAP_LEAF_ARRAY_NCHUNKS(num_integers * integer_size) -
-           ZAP_LEAF_ARRAY_NCHUNKS(le->le_value_length * le->le_int_size);
+           ZAP_LEAF_ARRAY_NCHUNKS(le->le_value_numints * le->le_value_intlen);
 
        if ((int)l->l_phys->l_hdr.lh_nfree < delta_chunks)
                return (EAGAIN);
 
-       /*
-        * We should search other chained leaves (via
-        * zap_entry_remove,create?) otherwise returning EAGAIN will
-        * just send us into an infinite loop if we have to chain
-        * another leaf block, rather than being able to split this
-        * block.
-        */
-
        zap_leaf_array_free(l, &le->le_value_chunk);
        le->le_value_chunk =
            zap_leaf_array_create(l, buf, integer_size, num_integers);
-       le->le_value_length = num_integers;
-       le->le_int_size = integer_size;
+       le->le_value_numints = num_integers;
+       le->le_value_intlen = integer_size;
        return (0);
 }
 
@@ -550,26 +569,25 @@ zap_entry_remove(zap_entry_handle_t *zeh)
 }
 
 int
-zap_entry_create(zap_leaf_t *l, const char *name, uint64_t h, uint32_t cd,
+zap_entry_create(zap_leaf_t *l, zap_name_t *zn, uint32_t cd,
     uint8_t integer_size, uint64_t num_integers, const void *buf,
     zap_entry_handle_t *zeh)
 {
        uint16_t chunk;
        uint16_t *chunkp;
        struct zap_leaf_entry *le;
-       uint64_t namelen, valuelen;
+       uint64_t valuelen;
        int numchunks;
+       uint64_t h = zn->zn_hash;
 
        valuelen = integer_size * num_integers;
-       namelen = strlen(name) + 1;
-       ASSERT(namelen >= 2);
 
-       numchunks = 1 + ZAP_LEAF_ARRAY_NCHUNKS(namelen) +
-           ZAP_LEAF_ARRAY_NCHUNKS(valuelen);
+       numchunks = 1 + ZAP_LEAF_ARRAY_NCHUNKS(zn->zn_key_orig_numints *
+           zn->zn_key_intlen) + ZAP_LEAF_ARRAY_NCHUNKS(valuelen);
        if (numchunks > ZAP_LEAF_NUMCHUNKS(l))
                return (E2BIG);
 
-       if (cd == ZAP_MAXCD) {
+       if (cd == ZAP_NEED_CD) {
                /* find the lowest unused cd */
                if (l->l_phys->l_hdr.lh_flags & ZLF_ENTRIES_CDSORTED) {
                        cd = 0;
@@ -586,7 +604,7 @@ zap_entry_create(zap_leaf_t *l, const char *name, uint64_t h, uint32_t cd,
                        }
                } else {
                        /* old unsorted format; do it the O(n^2) way */
-                       for (cd = 0; cd < ZAP_MAXCD; cd++) {
+                       for (cd = 0; ; cd++) {
                                for (chunk = *LEAF_HASH_ENTPTR(l, h);
                                    chunk != CHAIN_END; chunk = le->le_next) {
                                        le = ZAP_LEAF_ENTRY(l, chunk);
@@ -601,10 +619,10 @@ zap_entry_create(zap_leaf_t *l, const char *name, uint64_t h, uint32_t cd,
                        }
                }
                /*
-                * we would run out of space in a block before we could
-                * have ZAP_MAXCD entries
+                * We would run out of space in a block before we could
+                * store enough entries to run out of CD values.
                 */
-               ASSERT3U(cd, <, ZAP_MAXCD);
+               ASSERT3U(cd, <, zap_maxcd(zn->zn_zap));
        }
 
        if (l->l_phys->l_hdr.lh_nfree < numchunks)
@@ -614,12 +632,13 @@ zap_entry_create(zap_leaf_t *l, const char *name, uint64_t h, uint32_t cd,
        chunk = zap_leaf_chunk_alloc(l);
        le = ZAP_LEAF_ENTRY(l, chunk);
        le->le_type = ZAP_CHUNK_ENTRY;
-       le->le_name_chunk = zap_leaf_array_create(l, name, 1, namelen);
-       le->le_name_length = namelen;
+       le->le_name_chunk = zap_leaf_array_create(l, zn->zn_key_orig,
+           zn->zn_key_intlen, zn->zn_key_orig_numints);
+       le->le_name_numints = zn->zn_key_orig_numints;
        le->le_value_chunk =
            zap_leaf_array_create(l, buf, integer_size, num_integers);
-       le->le_value_length = num_integers;
-       le->le_int_size = integer_size;
+       le->le_value_numints = num_integers;
+       le->le_value_intlen = integer_size;
        le->le_hash = h;
        le->le_cd = cd;
 
@@ -631,7 +650,7 @@ zap_entry_create(zap_leaf_t *l, const char *name, uint64_t h, uint32_t cd,
 
        zeh->zeh_leaf = l;
        zeh->zeh_num_integers = num_integers;
-       zeh->zeh_integer_size = le->le_int_size;
+       zeh->zeh_integer_size = le->le_value_intlen;
        zeh->zeh_cd = le->le_cd;
        zeh->zeh_hash = le->le_hash;
        zeh->zeh_chunkp = chunkp;
@@ -673,7 +692,7 @@ zap_entry_normalization_conflict(zap_entry_handle_t *zeh, zap_name_t *zn,
                        allocdzn = B_TRUE;
                }
                if (zap_leaf_array_match(zeh->zeh_leaf, zn,
-                   le->le_name_chunk, le->le_name_length)) {
+                   le->le_name_chunk, le->le_name_numints)) {
                        if (allocdzn)
                                zap_name_free(zn);
                        return (B_TRUE);
@@ -836,9 +855,9 @@ zap_leaf_stats(zap_t *zap, zap_leaf_t *l, zap_stats_t *zs)
                        struct zap_leaf_entry *le =
                            ZAP_LEAF_ENTRY(l, chunk);
 
-                       n = 1 + ZAP_LEAF_ARRAY_NCHUNKS(le->le_name_length) +
-                           ZAP_LEAF_ARRAY_NCHUNKS(le->le_value_length *
-                           le->le_int_size);
+                       n = 1 + ZAP_LEAF_ARRAY_NCHUNKS(le->le_name_numints) +
+                           ZAP_LEAF_ARRAY_NCHUNKS(le->le_value_numints *
+                           le->le_value_intlen);
                        n = MIN(n, ZAP_HISTOGRAM_SIZE-1);
                        zs->zs_entries_using_n_chunks[n]++;