对映射取消映射时,将会调用 devmap_unmap(9E) 入口点。用户进程退出或调用 munmap(2) 系统调用会导致取消映射。
devmap_unmap() 的语法如下所示:
void xxdevmap_unmap(devmap_cookie_t handle, void *devprivate, offset_t off, size_t len, devmap_cookie_t new-handle1, void **new-devprivate1, devmap_cookie_t new-handle2, void **new-devprivate2);
其中:
正在释放的映射的映射句柄。
指向与映射关联的驱动程序专用数据的指针。
逻辑设备内存中取消映射开始处的偏移。
所取消映射的内存的长度(以字节为单位)。
系统用来描述新区域的句柄,该新区域在 off - 1 位置结束。new-handle1 的值可以为 NULL。
要由驱动程序通过用于新区域的专用驱动程序映射数据进行填充的指针,该新区域在 off -1 位置结束。如果 new-handle1 为 NULL,则会忽略 new-devprivate1。
系统用来描述新区域的句柄,该新区域在 off + len 位置开始。new-handle2 的值可以为 NULL。
要由驱动程序通过用于新区域的驱动程序专用映射数据进行填充的指针,该新区域在 off + len 位置开始。如果 new-handle2 为 NULL,则会忽略 new-devprivate2。
devmap_unmap() 例程预期会释放通过 devmap_map(9E) 或 devmap_dup(9E) 创建此映射时分配的任何驱动程序专用资源。如果只是取消映射部分映射,则驱动程序必须在释放旧的专用数据之前为其余映射分配新的专用数据。不必针对已释放的映射的句柄调用 devmap_unload(9F),即使此句柄指向具有有效转换的映射时也是如此。不过,为了避免将来出现 devmap_access(9E) 问题,设备驱动程序应确保当前的映射表示形式设置为“无当前映射”。
以下示例说明了一个典型的 devmap_unmap() 例程。
static void xxdevmap_unmap(devmap_cookie_t handle, void *devprivate, offset_t off, size_t len, devmap_cookie_t new_handle1, void **new_devprivate1, devmap_cookie_t new_handle2, void **new_devprivate2) { struct xxctx *ctxp = devprivate; struct xxstate *xsp = ctxp->xsp; mutex_enter(&xsp->ctx_lock); /* * If new_handle1 is not NULL, we are unmapping * at the end of the mapping. */ if (new_handle1 != NULL) { /* Create a new context structure for the mapping */ newctx = kmem_alloc(sizeof (struct xxctx), KM_SLEEP); newctx->xsp = xsp; if (ctxp->flags & MAP_PRIVATE) { /* allocate memory for the private context and copy it */ newctx->context = kmem_alloc(XXCTX_SIZE, KM_SLEEP); bcopy(ctxp->context, newctx->context, XXCTX_SIZE); } else { /* point to the shared context */ newctx->context = xsp->ctx_shared; } newctx->handle = new_handle1; newctx->offset = ctxp->offset; newctx->len = off - ctxp->offset; *new_devprivate1 = newctx; } /* * If new_handle2 is not NULL, we are unmapping * at the beginning of the mapping. */ if (new_handle2 != NULL) { /* Create a new context for the mapping */ newctx = kmem_alloc(sizeof (struct xxctx), KM_SLEEP); newctx->xsp = xsp; if (ctxp->flags & MAP_PRIVATE) { newctx->context = kmem_alloc(XXCTX_SIZE, KM_SLEEP); bcopy(ctxp->context, newctx->context, XXCTX_SIZE); } else { newctx->context = xsp->ctx_shared; } newctx->handle = new_handle2; newctx->offset = off + len; newctx->flags = ctxp->flags; newctx->len = ctxp->len - (off + len - ctxp->off); *new_devprivate2 = newctx; } if (xsp->current_ctx == ctxp) xsp->current_ctx = NULL; mutex_exit(&xsp->ctx_lock); if (ctxp->flags & MAP_PRIVATE) kmem_free(ctxp->context, XXCTX_SIZE); kmem_free(ctxp, sizeof (struct xxctx)); }