bhyve: Add support for handling disk resize events to block_if.
Allow clients of blockif to register a resize callback handler. When a callback is registered, register an EVFILT_VNODE kevent watching the backing store for a change in the file's attributes. If the size has changed when the kevent fires, invoke the clients' callback. Currently resize detection is limited to backing stores that support EVFILT_VNODE kevents such as regular files. Reviewed by: grehan, markj MFC after: 1 month Differential Revision: https://reviews.freebsd.org/D30504
This commit is contained in:
parent
67d60dcce6
commit
8794846a91
@ -115,6 +115,9 @@ struct blockif_ctxt {
|
||||
pthread_cond_t bc_cond;
|
||||
pthread_cond_t bc_paused_cond;
|
||||
pthread_cond_t bc_work_done_cond;
|
||||
blockif_resize_cb *bc_resize_cb;
|
||||
void *bc_resize_cb_arg;
|
||||
struct mevent *bc_resize_event;
|
||||
|
||||
/* Request elements and free/pending/busy queues */
|
||||
TAILQ_HEAD(, blockif_elem) bc_freeq;
|
||||
@ -532,7 +535,7 @@ blockif_open(nvlist_t *nvl, const char *ident)
|
||||
|
||||
#ifndef WITHOUT_CAPSICUM
|
||||
cap_rights_init(&rights, CAP_FSYNC, CAP_IOCTL, CAP_READ, CAP_SEEK,
|
||||
CAP_WRITE);
|
||||
CAP_WRITE, CAP_FSTAT, CAP_EVENT);
|
||||
if (ro)
|
||||
cap_rights_clear(&rights, CAP_FSYNC, CAP_WRITE);
|
||||
|
||||
@ -643,6 +646,62 @@ blockif_open(nvlist_t *nvl, const char *ident)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
blockif_resized(int fd, enum ev_type type, void *arg)
|
||||
{
|
||||
struct blockif_ctxt *bc;
|
||||
struct stat sb;
|
||||
|
||||
if (fstat(fd, &sb) != 0)
|
||||
return;
|
||||
|
||||
bc = arg;
|
||||
pthread_mutex_lock(&bc->bc_mtx);
|
||||
if (sb.st_size != bc->bc_size) {
|
||||
bc->bc_size = sb.st_size;
|
||||
bc->bc_resize_cb(bc, bc->bc_resize_cb_arg, bc->bc_size);
|
||||
}
|
||||
pthread_mutex_unlock(&bc->bc_mtx);
|
||||
}
|
||||
|
||||
int
|
||||
blockif_register_resize_callback(struct blockif_ctxt *bc, blockif_resize_cb *cb,
|
||||
void *cb_arg)
|
||||
{
|
||||
struct stat sb;
|
||||
int err;
|
||||
|
||||
if (cb == NULL)
|
||||
return (EINVAL);
|
||||
|
||||
pthread_mutex_lock(&bc->bc_mtx);
|
||||
if (bc->bc_resize_cb != NULL) {
|
||||
err = EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
assert(bc->bc_closing == 0);
|
||||
|
||||
if (fstat(bc->bc_fd, &sb) != 0) {
|
||||
err = errno;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bc->bc_resize_event = mevent_add_flags(bc->bc_fd, EVF_VNODE,
|
||||
EVFF_ATTRIB, blockif_resized, bc);
|
||||
if (bc->bc_resize_event == NULL) {
|
||||
err = ENXIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
bc->bc_resize_cb = cb;
|
||||
bc->bc_resize_cb_arg = cb_arg;
|
||||
out:
|
||||
pthread_mutex_unlock(&bc->bc_mtx);
|
||||
|
||||
return (err);
|
||||
}
|
||||
|
||||
static int
|
||||
blockif_request(struct blockif_ctxt *bc, struct blockif_req *breq,
|
||||
enum blockop op)
|
||||
@ -796,6 +855,8 @@ blockif_close(struct blockif_ctxt *bc)
|
||||
*/
|
||||
pthread_mutex_lock(&bc->bc_mtx);
|
||||
bc->bc_closing = 1;
|
||||
if (bc->bc_resize_event != NULL)
|
||||
mevent_disable(bc->bc_resize_event);
|
||||
pthread_mutex_unlock(&bc->bc_mtx);
|
||||
pthread_cond_broadcast(&bc->bc_cond);
|
||||
for (i = 0; i < BLOCKIF_NUMTHR; i++)
|
||||
|
@ -63,8 +63,13 @@ struct blockif_req {
|
||||
};
|
||||
|
||||
struct blockif_ctxt;
|
||||
|
||||
typedef void blockif_resize_cb(struct blockif_ctxt *, void *, size_t);
|
||||
|
||||
int blockif_legacy_config(nvlist_t *nvl, const char *opts);
|
||||
struct blockif_ctxt *blockif_open(nvlist_t *nvl, const char *ident);
|
||||
int blockif_register_resize_callback(struct blockif_ctxt *bc,
|
||||
blockif_resize_cb *cb, void *cb_arg);
|
||||
off_t blockif_size(struct blockif_ctxt *bc);
|
||||
void blockif_chs(struct blockif_ctxt *bc, uint16_t *c, uint8_t *h,
|
||||
uint8_t *s);
|
||||
|
Loading…
Reference in New Issue
Block a user