diff options
author | Christian Schoenebeck <qemu_oss@crudebyte.com> | 2019-10-07 17:02:45 +0200 |
---|---|---|
committer | Greg Kurz <groug@kaod.org> | 2019-10-10 11:36:23 +0200 |
commit | 6b6aa8285d7ecc172ed59903bb61f26c19ba2538 (patch) | |
tree | d4705bbc262e7c218c60b13fef30361fd07ae776 /hw/9pfs/9p.h | |
parent | f3fe4a2d92bb4ee5b599b8b1eb781b2ae68af36c (diff) | |
download | qemu-6b6aa8285d7ecc172ed59903bb61f26c19ba2538.zip |
9p: Use variable length suffixes for inode remapping
Use variable length suffixes for inode remapping instead of the fixed
16 bit size prefixes before. With this change the inode numbers on guest
will typically be much smaller (e.g. around >2^1 .. >2^7 instead of >2^48
with the previous fixed size inode remapping.
Additionally this solution is more efficient, since inode numbers in
practice can take almost their entire 64 bit range on guest as well, so
there is less likely a need for generating and tracking additional suffixes,
which might also be beneficial for nested virtualization where each level of
virtualization would shift up the inode bits and increase the chance of
expensive remapping actions.
The "Exponential Golomb" algorithm is used as basis for generating the
variable length suffixes. The algorithm has a parameter k which controls the
distribution of bits on increasing indeces (minimum bits at low index vs.
maximum bits at high index). With k=0 the generated suffixes look like:
Index Dec/Bin -> Generated Suffix Bin
1 [1] -> [1] (1 bits)
2 [10] -> [010] (3 bits)
3 [11] -> [110] (3 bits)
4 [100] -> [00100] (5 bits)
5 [101] -> [10100] (5 bits)
6 [110] -> [01100] (5 bits)
7 [111] -> [11100] (5 bits)
8 [1000] -> [0001000] (7 bits)
9 [1001] -> [1001000] (7 bits)
10 [1010] -> [0101000] (7 bits)
11 [1011] -> [1101000] (7 bits)
12 [1100] -> [0011000] (7 bits)
...
65533 [1111111111111101] -> [1011111111111111000000000000000] (31 bits)
65534 [1111111111111110] -> [0111111111111111000000000000000] (31 bits)
65535 [1111111111111111] -> [1111111111111111000000000000000] (31 bits)
Hence minBits=1 maxBits=31
And with k=5 they would look like:
Index Dec/Bin -> Generated Suffix Bin
1 [1] -> [000001] (6 bits)
2 [10] -> [100001] (6 bits)
3 [11] -> [010001] (6 bits)
4 [100] -> [110001] (6 bits)
5 [101] -> [001001] (6 bits)
6 [110] -> [101001] (6 bits)
7 [111] -> [011001] (6 bits)
8 [1000] -> [111001] (6 bits)
9 [1001] -> [000101] (6 bits)
10 [1010] -> [100101] (6 bits)
11 [1011] -> [010101] (6 bits)
12 [1100] -> [110101] (6 bits)
...
65533 [1111111111111101] -> [0011100000000000100000000000] (28 bits)
65534 [1111111111111110] -> [1011100000000000100000000000] (28 bits)
65535 [1111111111111111] -> [0111100000000000100000000000] (28 bits)
Hence minBits=6 maxBits=28
Signed-off-by: Christian Schoenebeck <qemu_oss@crudebyte.com>
Signed-off-by: Greg Kurz <groug@kaod.org>
Diffstat (limited to 'hw/9pfs/9p.h')
-rw-r--r-- | hw/9pfs/9p.h | 44 |
1 files changed, 41 insertions, 3 deletions
diff --git a/hw/9pfs/9p.h b/hw/9pfs/9p.h index 35a362c0d7..3904f82901 100644 --- a/hw/9pfs/9p.h +++ b/hw/9pfs/9p.h @@ -236,13 +236,49 @@ struct V9fsFidState V9fsFidState *rclm_lst; }; -#define QPATH_INO_MASK ((1ULL << 48) - 1) +typedef enum AffixType_t { + AffixType_Prefix, + AffixType_Suffix, /* A.k.a. postfix. */ +} AffixType_t; + +/** + * @brief Unique affix of variable length. + * + * An affix is (currently) either a suffix or a prefix, which is either + * going to be prepended (prefix) or appended (suffix) with some other + * number for the goal to generate unique numbers. Accordingly the + * suffixes (or prefixes) we generate @b must all have the mathematical + * property of being suffix-free (or prefix-free in case of prefixes) + * so that no matter what number we concatenate the affix with, that we + * always reliably get unique numbers as result after concatenation. + */ +typedef struct VariLenAffix { + AffixType_t type; /* Whether this affix is a suffix or a prefix. */ + uint64_t value; /* Actual numerical value of this affix. */ + /* + * Lenght of the affix, that is how many (of the lowest) bits of @c value + * must be used for appending/prepending this affix to its final resulting, + * unique number. + */ + int bits; +} VariLenAffix; + +/* See qid_inode_prefix_hash_bits(). */ +typedef struct { + dev_t dev; /* FS device on host. */ + /* + * How many (high) bits of the original inode number shall be used for + * hashing. + */ + int prefix_bits; +} QpdEntry; /* QID path prefix entry, see stat_to_qid */ typedef struct { dev_t dev; uint16_t ino_prefix; - uint16_t qp_prefix; + uint32_t qp_affix_index; + VariLenAffix qp_affix; } QppEntry; /* QID path full entry, as above */ @@ -274,9 +310,11 @@ struct V9fsState V9fsConf fsconf; V9fsQID root_qid; dev_t dev_id; + struct qht qpd_table; struct qht qpp_table; struct qht qpf_table; - uint16_t qp_prefix_next; + uint64_t qp_ndevices; /* Amount of entries in qpd_table. */ + uint16_t qp_affix_next; uint64_t qp_fullpath_next; }; |