int vmm_blockdev_register(struct vmm_blockdev *bdev) { int rc; struct vmm_classdev *cd; struct vmm_blockdev_event event; if (!bdev) { return VMM_EFAIL; } if (!(bdev->flags & VMM_BLOCKDEV_RDONLY) && !(bdev->flags & VMM_BLOCKDEV_RW)) { return VMM_EINVALID; } cd = vmm_malloc(sizeof(struct vmm_classdev)); if (!cd) { rc = VMM_ENOMEM; goto fail; } INIT_LIST_HEAD(&cd->head); if (strlcpy(cd->name, bdev->name, sizeof(cd->name)) >= sizeof(cd->name)) { rc = VMM_EOVERFLOW; goto free_classdev; } cd->dev = bdev->dev; cd->priv = bdev; rc = vmm_devdrv_register_classdev(VMM_BLOCKDEV_CLASS_NAME, cd); if (rc) { goto free_classdev; } /* Broadcast register event */ event.bdev = bdev; event.data = NULL; vmm_blocking_notifier_call(&bdev_notifier_chain, VMM_BLOCKDEV_EVENT_REGISTER, &event); return VMM_OK; free_classdev: vmm_free(cd); fail: return rc; }
int vmm_blockdev_unregister(struct vmm_blockdev *bdev) { int rc; struct dlist *l; struct vmm_blockdev *child_bdev; struct vmm_blockdev_event event; struct vmm_classdev *cd; if (!bdev) { return VMM_EFAIL; } /* Unreg & free child block devices */ vmm_mutex_lock(&bdev->child_lock); while (!list_empty(&bdev->child_list)) { l = list_pop(&bdev->child_list); child_bdev = list_entry(l, struct vmm_blockdev, head); if ((rc = vmm_blockdev_unregister(child_bdev))) { vmm_mutex_unlock(&bdev->child_lock); return rc; } __blockdev_free(child_bdev, FALSE); } vmm_mutex_unlock(&bdev->child_lock); /* Broadcast unregister event */ event.bdev = bdev; event.data = NULL; vmm_blocking_notifier_call(&bdev_notifier_chain, VMM_BLOCKDEV_EVENT_UNREGISTER, &event); cd = vmm_devdrv_find_classdev(VMM_BLOCKDEV_CLASS_NAME, bdev->name); if (!cd) { return VMM_EFAIL; } rc = vmm_devdrv_unregister_classdev(VMM_BLOCKDEV_CLASS_NAME, cd); if (!rc) { vmm_free(cd); } return rc; }
/** * Notify clients of fb_events */ int fb_notifier_call_chain(unsigned long val, void *v) { return vmm_blocking_notifier_call(&fb_notifier_list, val, v); }