• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

google / alioth / 17119523075

21 Aug 2025 01:27AM UTC coverage: 11.963% (+1.6%) from 10.411%
17119523075

push

github

Lencerf
feat(virtio): support packed queue

Signed-off-by: Changyuan Lyu <changyuanl@google.com>

91 of 132 new or added lines in 5 files covered. (68.94%)

155 existing lines in 8 files now uncovered.

838 of 7005 relevant lines covered (11.96%)

17.32 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.59
/alioth/src/virtio/queue/queue.rs
1
// Copyright 2024 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
#[cfg(test)]
16
#[path = "queue_test.rs"]
17
mod tests;
18

19
pub mod packed;
20
pub mod split;
21

22
use std::collections::HashMap;
23
use std::fmt::Debug;
24
use std::hash::Hash;
25
use std::io::{ErrorKind, IoSlice, IoSliceMut, Read, Write};
26
use std::sync::atomic::{AtomicBool, AtomicU16, AtomicU64, Ordering, fence};
27

28
use bitflags::bitflags;
29

30
use crate::virtio::{IrqSender, Result, error};
31

32
pub const QUEUE_SIZE_MAX: u16 = 256;
33

34
bitflags! {
10✔
35
    #[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
36
    pub struct DescFlag: u16 {
37
        const NEXT = 1;
38
        const WRITE = 2;
39
        const INDIRECT = 4;
40
        const AVAIL = 1 << 7;
41
        const USED = 1 << 15;
42
    }
43
}
44

45
#[derive(Debug, Default)]
46
pub struct QueueReg {
47
    pub size: AtomicU16,
48
    pub desc: AtomicU64,
49
    pub driver: AtomicU64,
50
    pub device: AtomicU64,
51
    pub enabled: AtomicBool,
52
}
53

54
#[derive(Debug)]
55
pub struct DescChain<'m> {
56
    id: u16,
57
    index: u16,
58
    count: u16,
59
    pub readable: Vec<IoSlice<'m>>,
60
    pub writable: Vec<IoSliceMut<'m>>,
61
}
62

63
impl DescChain<'_> {
64
    pub fn id(&self) -> u16 {
9✔
65
        self.id
9✔
66
    }
67
}
68

69
mod private {
70
    use crate::virtio::Result;
71
    use crate::virtio::queue::DescChain;
72

73
    pub trait VirtQueuePrivate<'m> {
74
        type Index: Clone + Copy;
75
        const INIT_INDEX: Self::Index;
76
        fn desc_avail(&self, index: Self::Index) -> bool;
77
        fn get_desc_chain(&self, index: Self::Index) -> Result<Option<DescChain<'m>>>;
78
        fn push_used(&mut self, chain: DescChain, len: u32);
79
        fn enable_notification(&self, enabled: bool);
80
        fn interrupt_enabled(&self, count: u16) -> bool;
81
        fn next_index(&self, chain: &DescChain) -> Self::Index;
82
    }
83
}
84

85
pub trait VirtQueue<'m>: private::VirtQueuePrivate<'m> {
86
    fn reg(&self) -> &QueueReg;
87
}
88

89
#[derive(Debug)]
90
pub enum Status {
91
    Done { len: u32 },
92
    Deferred,
93
    Break,
94
}
95

96
pub struct Queue<'m, Q>
97
where
98
    Q: VirtQueue<'m>,
99
{
100
    q: Q,
101
    iter: Q::Index,
102
    deferred: HashMap<u16, DescChain<'m>>,
103
}
104

105
impl<'m, Q> Queue<'m, Q>
106
where
107
    Q: VirtQueue<'m>,
108
{
109
    pub fn new(q: Q) -> Self {
7✔
110
        Self {
111
            q,
112
            iter: Q::INIT_INDEX,
113
            deferred: HashMap::new(),
7✔
114
        }
115
    }
116

117
    pub fn reg(&self) -> &QueueReg {
3✔
118
        self.q.reg()
3✔
119
    }
120

121
    pub fn handle_deferred(
9✔
122
        &mut self,
123
        id: u16,
124
        q_index: u16,
125
        irq_sender: &impl IrqSender,
126
        mut op: impl FnMut(&mut DescChain) -> Result<u32>,
127
    ) -> Result<()> {
128
        let Some(mut chain) = self.deferred.remove(&id) else {
22✔
129
            return error::InvalidDescriptor { id }.fail();
5✔
130
        };
131
        let len = op(&mut chain)?;
8✔
NEW
132
        let count = chain.count;
2✔
UNCOV
133
        self.q.push_used(chain, len);
2✔
134
        if self.q.interrupt_enabled(count) {
6✔
135
            irq_sender.queue_irq(q_index);
10✔
136
        }
UNCOV
137
        Ok(())
2✔
138
    }
139

140
    pub fn handle_desc(
37✔
141
        &mut self,
142
        q_index: u16,
143
        irq_sender: &impl IrqSender,
144
        mut op: impl FnMut(&mut DescChain) -> Result<Status>,
145
    ) -> Result<()> {
146
        let mut send_irq = false;
71✔
147
        let mut ret = Ok(());
71✔
UNCOV
148
        'out: loop {
×
149
            if !self.q.desc_avail(self.iter) {
102✔
150
                break;
22✔
151
            }
152
            self.q.enable_notification(false);
55✔
153
            while let Some(mut chain) = self.q.get_desc_chain(self.iter)? {
160✔
UNCOV
154
                let next_iter = self.q.next_index(&chain);
6✔
NEW
155
                let count = chain.count;
3✔
UNCOV
156
                match op(&mut chain) {
6✔
157
                    Err(e) => {
6✔
158
                        ret = Err(e);
10✔
159
                        self.q.enable_notification(true);
10✔
160
                        break 'out;
4✔
161
                    }
162
                    Ok(Status::Break) => break 'out,
8✔
163
                    Ok(Status::Done { len }) => {
14✔
UNCOV
164
                        self.q.push_used(chain, len);
2✔
165
                        send_irq = send_irq || self.q.interrupt_enabled(count);
14✔
166
                    }
167
                    Ok(Status::Deferred) => {
4✔
168
                        self.deferred.insert(chain.id(), chain);
18✔
169
                    }
170
                }
171
                self.iter = next_iter;
19✔
172
            }
173
            self.q.enable_notification(true);
17✔
UNCOV
174
            fence(Ordering::SeqCst);
3✔
175
        }
176
        if send_irq {
49✔
177
            fence(Ordering::SeqCst);
38✔
178
            irq_sender.queue_irq(q_index);
26✔
179
        }
UNCOV
180
        ret
3✔
181
    }
182
}
183

184
pub fn copy_from_reader(mut reader: impl Read) -> impl FnMut(&mut DescChain) -> Result<Status> {
20✔
185
    move |chain| {
16✔
186
        let ret = reader.read_vectored(&mut chain.writable);
58✔
187
        match ret {
8✔
UNCOV
188
            Ok(0) => {
×
189
                let size: usize = chain.writable.iter().map(|s| s.len()).sum();
12✔
UNCOV
190
                if size == 0 {
2✔
191
                    Ok(Status::Done { len: 0 })
3✔
192
                } else {
193
                    Ok(Status::Break)
3✔
194
                }
195
            }
196
            Ok(len) => Ok(Status::Done { len: len as u32 }),
14✔
197
            Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(Status::Break),
13✔
198
            Err(e) => Err(e.into()),
4✔
199
        }
200
    }
201
}
202

203
pub fn copy_to_writer(mut writer: impl Write) -> impl FnMut(&mut DescChain) -> Result<Status> {
20✔
204
    move |chain| {
16✔
205
        let ret = writer.write_vectored(&chain.readable);
58✔
206
        match ret {
8✔
UNCOV
207
            Ok(0) => {
×
208
                let size: usize = chain.readable.iter().map(|s| s.len()).sum();
12✔
UNCOV
209
                if size == 0 {
2✔
210
                    Ok(Status::Done { len: 0 })
3✔
211
                } else {
212
                    Ok(Status::Break)
3✔
213
                }
214
            }
215
            Ok(_) => Ok(Status::Done { len: 0 }),
8✔
216
            Err(e) if e.kind() == ErrorKind::WouldBlock => Ok(Status::Break),
13✔
217
            Err(e) => Err(e.into()),
4✔
218
        }
219
    }
220
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc