@@ -48,6 +48,8 @@ pub struct Entropy {
48
48
49
49
// Device specific fields
50
50
rate_limiter : RateLimiter ,
51
+
52
+ buffer : IoVecBufferMut ,
51
53
}
52
54
53
55
impl Entropy {
@@ -75,6 +77,7 @@ impl Entropy {
75
77
queue_events,
76
78
irq_trigger,
77
79
rate_limiter,
80
+ buffer : IoVecBufferMut :: default ( ) ,
78
81
} )
79
82
}
80
83
@@ -88,13 +91,13 @@ impl Entropy {
88
91
. map_err ( DeviceError :: FailedSignalingIrq )
89
92
}
90
93
91
- fn rate_limit_request ( rate_limiter : & mut RateLimiter , bytes : u64 ) -> bool {
92
- if !rate_limiter. consume ( 1 , TokenType :: Ops ) {
94
+ fn rate_limit_request ( & mut self , bytes : u64 ) -> bool {
95
+ if !self . rate_limiter . consume ( 1 , TokenType :: Ops ) {
93
96
return false ;
94
97
}
95
98
96
- if !rate_limiter. consume ( bytes, TokenType :: Bytes ) {
97
- rate_limiter. manual_replenish ( 1 , TokenType :: Ops ) ;
99
+ if !self . rate_limiter . consume ( bytes, TokenType :: Bytes ) {
100
+ self . rate_limiter . manual_replenish ( 1 , TokenType :: Ops ) ;
98
101
return false ;
99
102
}
100
103
@@ -106,53 +109,52 @@ impl Entropy {
106
109
rate_limiter. manual_replenish ( bytes, TokenType :: Bytes ) ;
107
110
}
108
111
109
- fn handle_one ( & self , iovec : & mut IoVecBufferMut ) -> Result < u32 , EntropyError > {
112
+ fn handle_one ( & mut self ) -> Result < u32 , EntropyError > {
110
113
// If guest provided us with an empty buffer just return directly
111
- if iovec . len ( ) == 0 {
114
+ if self . buffer . len ( ) == 0 {
112
115
return Ok ( 0 ) ;
113
116
}
114
117
115
- let mut rand_bytes = vec ! [ 0 ; iovec . len( ) as usize ] ;
118
+ let mut rand_bytes = vec ! [ 0 ; self . buffer . len( ) as usize ] ;
116
119
rand:: fill ( & mut rand_bytes) . map_err ( |err| {
117
120
METRICS . host_rng_fails . inc ( ) ;
118
121
err
119
122
} ) ?;
120
123
121
124
// It is ok to unwrap here. We are writing `iovec.len()` bytes at offset 0.
122
- iovec . write_all_volatile_at ( & rand_bytes, 0 ) . unwrap ( ) ;
123
- Ok ( iovec . len ( ) )
125
+ self . buffer . write_all_volatile_at ( & rand_bytes, 0 ) . unwrap ( ) ;
126
+ Ok ( self . buffer . len ( ) )
124
127
}
125
128
126
129
fn process_entropy_queue ( & mut self ) {
127
- // This is safe since we checked in the event handler that the device is activated.
128
- let mem = self . device_state . mem ( ) . unwrap ( ) ;
129
-
130
130
let mut used_any = false ;
131
131
while let Some ( desc) = self . queues [ RNG_QUEUE ] . pop ( ) {
132
+ // This is safe since we checked in the event handler that the device is activated.
133
+ let mem = self . device_state . mem ( ) . unwrap ( ) ;
132
134
let index = desc. index ;
133
135
METRICS . entropy_event_count . inc ( ) ;
134
136
135
- // SAFETY: This descriptor chain is only loaded once
136
- // virtio requests are handled sequentially so no two IoVecBuffers
137
- // are live at the same time, meaning this has exclusive ownership over the memory
138
- let bytes = match unsafe { IoVecBufferMut :: from_descriptor_chain ( mem, desc) } {
139
- Ok ( mut iovec ) => {
137
+ // SAFETY: This descriptor chain points to a single `DescriptorChain` memory buffer,
138
+ // no other `IoVecBufferMut` object points to the same `DescriptorChain` at the same
139
+ // time and we clear the `iovec` after we process the request.
140
+ let bytes = match unsafe { self . buffer . load_descriptor_chain ( mem, desc) } {
141
+ Ok ( ( ) ) => {
140
142
debug ! (
141
143
"entropy: guest request for {} bytes of entropy" ,
142
- iovec . len( )
144
+ self . buffer . len( )
143
145
) ;
144
146
145
147
// Check for available rate limiting budget.
146
148
// If not enough budget is available, leave the request descriptor in the queue
147
149
// to handle once we do have budget.
148
- if !Self :: rate_limit_request ( & mut self . rate_limiter , u64:: from ( iovec . len ( ) ) ) {
150
+ if !self . rate_limit_request ( u64:: from ( self . buffer . len ( ) ) ) {
149
151
debug ! ( "entropy: throttling entropy queue" ) ;
150
152
METRICS . entropy_rate_limiter_throttled . inc ( ) ;
151
153
self . queues [ RNG_QUEUE ] . undo_pop ( ) ;
152
154
break ;
153
155
}
154
156
155
- self . handle_one ( & mut iovec ) . unwrap_or_else ( |err| {
157
+ self . handle_one ( ) . unwrap_or_else ( |err| {
156
158
error ! ( "entropy: {err}" ) ;
157
159
METRICS . entropy_event_fails . inc ( ) ;
158
160
0
@@ -444,8 +446,8 @@ mod tests {
444
446
// This should succeed, we should have one more descriptor
445
447
let desc = entropy_dev. queues_mut ( ) [ RNG_QUEUE ] . pop ( ) . unwrap ( ) ;
446
448
// SAFETY: This descriptor chain is only loaded into one buffer
447
- let mut iovec = unsafe { IoVecBufferMut :: from_descriptor_chain ( & mem, desc) . unwrap ( ) } ;
448
- entropy_dev. handle_one ( & mut iovec ) . unwrap ( ) ;
449
+ entropy_dev . buffer = unsafe { IoVecBufferMut :: from_descriptor_chain ( & mem, desc) . unwrap ( ) } ;
450
+ entropy_dev. handle_one ( ) . unwrap ( ) ;
449
451
}
450
452
451
453
#[ test]
0 commit comments