Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016, Citrix Systems, Inc.
3 : : *
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * 2. Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : * 3. Neither the name of the copyright holder nor the names of its
15 : : * contributors may be used to endorse or promote products derived from
16 : : * this software without specific prior written permission.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 : : * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 : : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 : : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : #ifndef _TAPDISK_VBD_H_
32 : : #define _TAPDISK_VBD_H_
33 : :
34 : : #include <sys/time.h>
35 : :
36 : : #include "tapdisk.h"
37 : : #include "scheduler.h"
38 : : #include "tapdisk-image.h"
39 : : #include "tapdisk-blktap.h"
40 : : #include "td-blkif.h"
41 : :
42 : : #define TD_VBD_REQUEST_TIMEOUT 120
43 : : #define TD_VBD_MAX_RETRIES 100
44 : : #define TD_VBD_RETRY_INTERVAL 1
45 : :
46 : : /*
47 : : * VBD states
48 : : */
49 : : #define TD_VBD_DEAD 0x0001
50 : : #define TD_VBD_CLOSED 0x0002
51 : : #define TD_VBD_QUIESCE_REQUESTED 0x0004
52 : : #define TD_VBD_QUIESCED 0x0008
53 : : #define TD_VBD_PAUSE_REQUESTED 0x0010
54 : : #define TD_VBD_PAUSED 0x0020
55 : : #define TD_VBD_SHUTDOWN_REQUESTED 0x0040
56 : : #define TD_VBD_LOCKING 0x0080
57 : : #define TD_VBD_LOG_DROPPED 0x0100
58 : : #define TD_VBD_RESUME_FAILED 0x0200
59 : :
60 : : #define TD_VBD_SECONDARY_DISABLED 0
61 : : #define TD_VBD_SECONDARY_MIRROR 1
62 : : #define TD_VBD_SECONDARY_STANDBY 2
63 : :
64 : : struct td_nbdserver;
65 : :
66 : : struct td_vbd_rrd {
67 : :
68 : : struct shm shm;
69 : :
70 : : /*
71 : : * Previous value of td_vbd_handle.errors. We maintain this in order to
72 : : * tell whether we need to update the RRD.
73 : : */
74 : : uint64_t last_errors;
75 : :
76 : : time_t last;
77 : : };
78 : :
79 : : struct td_vbd_handle {
80 : : /**
81 : : * type:/path/to/file
82 : : */
83 : : char *name;
84 : :
85 : : td_blktap_t *tap;
86 : :
87 : : td_uuid_t uuid;
88 : :
89 : : /**
90 : : * shared rings
91 : : */
92 : : struct list_head rings;
93 : :
94 : : /**
95 : : * List of rings that contain pending requests but a disconnection was
96 : : * issued. We need to maintain these rings until all their pending requests
97 : : * complete. When the last request completes, the ring is destroyed and
98 : : * removed from this list.
99 : : */
100 : : struct list_head dead_rings;
101 : :
102 : : td_flag_t flags;
103 : :
104 : : /**
105 : : * VBD state (TD_VBD_XXX, excluding SECONDARY and request-related)
106 : : */
107 : : td_flag_t state;
108 : :
109 : : /**
110 : : * List of images: the leaf is at the head, the tree root is at the tail.
111 : : */
112 : : struct list_head images;
113 : :
114 : : int parent_devnum;
115 : : char *secondary_name;
116 : : td_image_t *secondary;
117 : : uint8_t secondary_mode;
118 : :
119 : : int FIXME_enospc_redirect_count_enabled;
120 : : uint64_t FIXME_enospc_redirect_count;
121 : :
122 : : /*
123 : : * when we encounter ENOSPC on the primary leaf image in mirror mode,
124 : : * we need to remove it from the VBD chain so that writes start going
125 : : * on the secondary leaf. However, we cannot free the image at that
126 : : * time since it might still have in-flight treqs referencing it.
127 : : * Therefore, we move it into 'retired' until shutdown.
128 : : */
129 : : td_image_t *retired;
130 : :
131 : : int nbd_mirror_failed;
132 : :
133 : : struct list_head new_requests;
134 : : struct list_head pending_requests;
135 : : struct list_head failed_requests;
136 : : struct list_head completed_requests;
137 : :
138 : : td_vbd_request_t request_list[MAX_REQUESTS]; /* XXX */
139 : :
140 : : struct list_head next;
141 : :
142 : : uint16_t req_timeout; /* in seconds */
143 : : struct timeval ts;
144 : :
145 : : uint64_t received;
146 : : uint64_t returned;
147 : : uint64_t kicked;
148 : : uint64_t secs_pending;
149 : : uint64_t retries;
150 : : uint64_t errors;
151 : : td_sector_count_t secs;
152 : :
153 : : struct td_nbdserver *nbdserver;
154 : : struct td_nbdserver *nbdserver_new;
155 : :
156 : : /**
157 : : * We keep a copy of the disk info because we might receive a disk info
158 : : * request while we're in the paused state.
159 : : */
160 : : td_disk_info_t disk_info;
161 : :
162 : : struct td_vbd_rrd rrd;
163 : : stats_t vdi_stats;
164 : :
165 : : char *logpath;
166 : :
167 : : struct td_vbd_encryption encryption;
168 : :
169 : : bool watchdog_warned;
170 : : };
171 : :
172 : : #define tapdisk_vbd_for_each_request(vreq, tmp, list) \
173 : : list_for_each_entry_safe((vreq), (tmp), (list), next)
174 : :
175 : : #define tapdisk_vbd_for_each_image(vbd, image, tmp) \
176 : : tapdisk_for_each_image_safe(image, tmp, &vbd->images)
177 : :
178 : : #define tapdisk_vbd_for_each_blkif(vbd, blkif, tmp) \
179 : : list_for_each_entry_safe((blkif), (tmp), (&vbd->rings), entry)
180 : :
181 : : static inline void
182 : : tapdisk_vbd_move_request(td_vbd_request_t *vreq, struct list_head *dest)
183 : : {
184 : 1 : list_del(&vreq->next);
185 : 1 : INIT_LIST_HEAD(&vreq->next);
186 : 1 : list_add_tail(&vreq->next, dest);
187 : 0 : vreq->list_head = dest;
188 : : }
189 : :
190 : : td_vbd_t *tapdisk_vbd_create(td_uuid_t);
191 : : int tapdisk_vbd_initialize(int, int, td_uuid_t);
192 : : int tapdisk_vbd_open(td_vbd_t *, const char *, int, const char *, td_flag_t);
193 : : int tapdisk_vbd_close(td_vbd_t *);
194 : :
195 : : /**
196 : : * Opens a VDI.
197 : : *
198 : : * @params vbd output parameter that receives a handle to the opened VDI
199 : : * @param params type:/path/to/file
200 : : * @params flags TD_OPEN_* TODO which TD_OPEN_* flags are honored? How does
201 : : * each flag affect the behavior of this functions? Move TD_OPEN_* flag
202 : : * definitions close to this function (check if they're used only by this
203 : : * function)?
204 : : * @param prt_devnum parent minor (optional)
205 : : * @returns 0 on success
206 : : */
207 : : int tapdisk_vbd_open_vdi(td_vbd_t * vbd, const char *params, td_flag_t flags,
208 : : int prt_devnum);
209 : : void tapdisk_vbd_close_vdi(td_vbd_t *);
210 : :
211 : : int tapdisk_vbd_attach(td_vbd_t *, const char *, int);
212 : : void tapdisk_vbd_detach(td_vbd_t *);
213 : :
214 : : int tapdisk_vbd_queue_request(td_vbd_t *, td_vbd_request_t *);
215 : : void tapdisk_vbd_forward_request(td_request_t);
216 : :
217 : : int tapdisk_vbd_get_disk_info(td_vbd_t *, td_disk_info_t *);
218 : : int tapdisk_vbd_retry_needed(td_vbd_t *);
219 : : int tapdisk_vbd_quiesce_queue(td_vbd_t *);
220 : : int tapdisk_vbd_start_queue(td_vbd_t *);
221 : : int tapdisk_vbd_issue_requests(td_vbd_t *);
222 : : int tapdisk_vbd_kill_queue(td_vbd_t *);
223 : : int tapdisk_vbd_pause(td_vbd_t *);
224 : : void tapdisk_vbd_squash_pause_logging(bool squash);
225 : : int tapdisk_vbd_resume(td_vbd_t *, const char *);
226 : : void tapdisk_vbd_kick(td_vbd_t *);
227 : : void tapdisk_vbd_check_state(td_vbd_t *);
228 : : void tapdisk_vbd_free(td_vbd_t *);
229 : :
230 : : void tapdisk_vbd_complete_td_request(td_request_t, int);
231 : : int add_extent(tapdisk_extents_t *, td_request_t *);
232 : : int tapdisk_vbd_issue_request(td_vbd_t *, td_vbd_request_t *);
233 : :
234 : : /**
235 : : * Checks whether there are new requests and if so it submits them, prodived
236 : : * that the queue has not been quiesced.
237 : : *
238 : : * Returns 1 if new requests have been issued, otherwise it returns 0.
239 : : */
240 : : int tapdisk_vbd_recheck_state(td_vbd_t *);
241 : :
242 : : void tapdisk_vbd_check_progress(td_vbd_t *);
243 : : void tapdisk_vbd_debug(td_vbd_t *);
244 : : int tapdisk_vbd_start_nbdservers(td_vbd_t *);
245 : : void tapdisk_vbd_stats(td_vbd_t *, td_stats_t *);
246 : : void tapdisk_vbd_complete_block_status_request(td_request_t, int);
247 : :
248 : : /**
249 : : * Tells whether the VBD contains at least one dead ring.
250 : : */
251 : : bool tapdisk_vbd_contains_dead_rings(td_vbd_t * vbd);
252 : : #endif
|