* [PATCH] drm/vmwgfx: Remove fence event code
@ 2026-10-29 16:54 Ian Forbes
2026-10-29 22:04 ` Zack Rusin
2026-10-30 0:33 ` Maaz Mombasawala <maaz.mombasawala@broadcom.com>
0 siblings, 2 replies; 3+ messages in thread
From: Ian Forbes @ 2026-10-29 16:54 UTC (permalink / raw)
To: dri-devel
Cc: bcm-kernel-feedback-list, zack.rusin, maaz.mombasawala,
Ian Forbes
The last vmwgfx internal use of this code was removed in commit
2e10cdc6e85d ("drm/vmwgfx: Remove explicit and broken vblank handling")
The vmw_fence_event ioctl was introduced in commit
57c5ee79acba ("vmwgfx: Add fence events") which claimed it would be used
by the xf86-video-vmware Xorg driver but the git history shows that it was
never used in that driver; nor was it used by mesa.
Remove this code as we've had a number of bug reports related to it.
Signed-off-by: Ian Forbes <ian.forbes@broadcom.com>
---
drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 241 +-------------------------
drivers/gpu/drm/vmwgfx/vmwgfx_fence.h | 6 -
2 files changed, 1 insertion(+), 246 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
index 384c6736cf6b..004ed060cf54 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
@@ -23,27 +23,6 @@ struct vmw_user_fence {
struct vmw_fence_obj fence;
};
-/**
- * struct vmw_event_fence_action - fence callback that delivers a DRM event.
- *
- * @base: For use with dma_fence_add_callback(...)
- * @event: A pointer to the pending event.
- * @dev: Pointer to a struct drm_device so we can access the event stuff.
- * @tv_sec: If non-null, the variable pointed to will be assigned
- * current time tv_sec val when the fence signals.
- * @tv_usec: Must be set if @tv_sec is set, and the variable pointed to will
- * be assigned the current time tv_usec val when the fence signals.
- */
-struct vmw_event_fence_action {
- struct dma_fence_cb base;
-
- struct drm_pending_event *event;
- struct drm_device *dev;
-
- uint32_t *tv_sec;
- uint32_t *tv_usec;
-};
-
static struct vmw_fence_manager *
fman_from_fence(struct vmw_fence_obj *fence)
{
@@ -524,226 +503,8 @@ int vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data,
arg->handle);
}
-/**
- * vmw_event_fence_action_seq_passed
- *
- * @f: The struct dma_fence which provides timestamp for the action event
- * @cb: The struct dma_fence_cb callback for the action event.
- *
- * This function is called when the seqno of the fence has passed
- * and it is always called from atomic context.
- * It queues the event on the submitter's event list.
- */
-static void vmw_event_fence_action_seq_passed(struct dma_fence *f,
- struct dma_fence_cb *cb)
-{
- struct vmw_event_fence_action *eaction =
- container_of(cb, struct vmw_event_fence_action, base);
- struct drm_device *dev = eaction->dev;
- struct drm_pending_event *event = eaction->event;
-
- if (unlikely(event == NULL))
- return;
-
- spin_lock_irq(&dev->event_lock);
-
- if (likely(eaction->tv_sec != NULL)) {
- struct timespec64 ts;
-
- ts = ktime_to_timespec64(f->timestamp);
- /* monotonic time, so no y2038 overflow */
- *eaction->tv_sec = ts.tv_sec;
- *eaction->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
- }
-
- drm_send_event_locked(dev, eaction->event);
- eaction->event = NULL;
- spin_unlock_irq(&dev->event_lock);
- dma_fence_put(f);
- kfree(eaction);
-}
-
-/**
- * vmw_event_fence_action_queue - Post an event for sending when a fence
- * object seqno has passed.
- *
- * @file_priv: The file connection on which the event should be posted.
- * @fence: The fence object on which to post the event.
- * @event: Event to be posted. This event should've been alloced
- * using k[mz]alloc, and should've been completely initialized.
- * @tv_sec: If non-null, the variable pointed to will be assigned
- * current time tv_sec val when the fence signals.
- * @tv_usec: Must be set if @tv_sec is set, and the variable pointed to will
- * be assigned the current time tv_usec val when the fence signals.
- * @interruptible: Interruptible waits if possible.
- *
- * As a side effect, the object pointed to by @event may have been
- * freed when this function returns. If this function returns with
- * an error code, the caller needs to free that object.
- */
-
-int vmw_event_fence_action_queue(struct drm_file *file_priv,
- struct vmw_fence_obj *fence,
- struct drm_pending_event *event,
- uint32_t *tv_sec,
- uint32_t *tv_usec,
- bool interruptible)
-{
- struct vmw_event_fence_action *eaction;
- struct vmw_fence_manager *fman = fman_from_fence(fence);
-
- eaction = kzalloc_obj(*eaction);
- if (unlikely(!eaction))
- return -ENOMEM;
-
- eaction->event = event;
- eaction->dev = &fman->dev_priv->drm;
- eaction->tv_sec = tv_sec;
- eaction->tv_usec = tv_usec;
-
- vmw_fence_obj_reference(fence); // Dropped in CB
- if (dma_fence_add_callback(&fence->base, &eaction->base,
- vmw_event_fence_action_seq_passed) < 0)
- vmw_event_fence_action_seq_passed(&fence->base, &eaction->base);
- return 0;
-}
-
-struct vmw_event_fence_pending {
- struct drm_pending_event base;
- struct drm_vmw_event_fence event;
-};
-
-static int vmw_event_fence_action_create(struct drm_file *file_priv,
- struct vmw_fence_obj *fence,
- uint32_t flags,
- uint64_t user_data,
- bool interruptible)
-{
- struct vmw_event_fence_pending *event;
- struct vmw_fence_manager *fman = fman_from_fence(fence);
- struct drm_device *dev = &fman->dev_priv->drm;
- int ret;
-
- event = kzalloc_obj(*event);
- if (unlikely(!event)) {
- DRM_ERROR("Failed to allocate an event.\n");
- ret = -ENOMEM;
- goto out_no_space;
- }
-
- event->event.base.type = DRM_VMW_EVENT_FENCE_SIGNALED;
- event->event.base.length = sizeof(event->event);
- event->event.user_data = user_data;
-
- ret = drm_event_reserve_init(dev, file_priv, &event->base, &event->event.base);
-
- if (unlikely(ret != 0)) {
- DRM_ERROR("Failed to allocate event space for this file.\n");
- kfree(event);
- goto out_no_space;
- }
-
- if (flags & DRM_VMW_FE_FLAG_REQ_TIME)
- ret = vmw_event_fence_action_queue(file_priv, fence,
- &event->base,
- &event->event.tv_sec,
- &event->event.tv_usec,
- interruptible);
- else
- ret = vmw_event_fence_action_queue(file_priv, fence,
- &event->base,
- NULL,
- NULL,
- interruptible);
- if (ret != 0)
- goto out_no_queue;
-
- return 0;
-
-out_no_queue:
- drm_event_cancel_free(dev, &event->base);
-out_no_space:
- return ret;
-}
-
int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
- struct vmw_private *dev_priv = vmw_priv(dev);
- struct drm_vmw_fence_event_arg *arg =
- (struct drm_vmw_fence_event_arg *) data;
- struct vmw_fence_obj *fence = NULL;
- struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
- struct ttm_object_file *tfile = vmw_fp->tfile;
- struct drm_vmw_fence_rep __user *user_fence_rep =
- (struct drm_vmw_fence_rep __user *)(unsigned long)
- arg->fence_rep;
- uint32_t handle;
- int ret;
-
- /*
- * Look up an existing fence object,
- * and if user-space wants a new reference,
- * add one.
- */
- if (arg->handle) {
- struct ttm_base_object *base =
- vmw_fence_obj_lookup(tfile, arg->handle);
-
- if (IS_ERR(base))
- return PTR_ERR(base);
-
- fence = &(container_of(base, struct vmw_user_fence,
- base)->fence);
- (void) vmw_fence_obj_reference(fence);
-
- if (user_fence_rep != NULL) {
- ret = ttm_ref_object_add(vmw_fp->tfile, base,
- NULL, false);
- if (unlikely(ret != 0)) {
- DRM_ERROR("Failed to reference a fence "
- "object.\n");
- goto out_no_ref_obj;
- }
- handle = base->handle;
- }
- ttm_base_object_unref(&base);
- }
-
- /*
- * Create a new fence object.
- */
- if (!fence) {
- ret = vmw_execbuf_fence_commands(file_priv, dev_priv,
- &fence,
- (user_fence_rep) ?
- &handle : NULL);
- if (unlikely(ret != 0)) {
- DRM_ERROR("Fence event failed to create fence.\n");
- return ret;
- }
- }
-
- BUG_ON(fence == NULL);
-
- ret = vmw_event_fence_action_create(file_priv, fence,
- arg->flags,
- arg->user_data,
- true);
- if (unlikely(ret != 0)) {
- if (ret != -ERESTARTSYS)
- DRM_ERROR("Failed to attach event to fence.\n");
- goto out_no_create;
- }
-
- vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
- handle, -1);
- vmw_fence_obj_unreference(&fence);
- return 0;
-out_no_create:
- if (user_fence_rep != NULL)
- ttm_ref_object_base_unref(tfile, handle);
-out_no_ref_obj:
- vmw_fence_obj_unreference(&fence);
- return ret;
+ return -ENOTTY; // Never Used
}
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
index e897cccae1ae..24d7b279ca4b 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
@@ -101,10 +101,4 @@ extern int vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
extern int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-extern int vmw_event_fence_action_queue(struct drm_file *filee_priv,
- struct vmw_fence_obj *fence,
- struct drm_pending_event *event,
- uint32_t *tv_sec,
- uint32_t *tv_usec,
- bool interruptible);
#endif /* _VMWGFX_FENCE_H_ */
--
2.56.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH] drm/vmwgfx: Remove fence event code
2026-10-29 16:54 [PATCH] drm/vmwgfx: Remove fence event code Ian Forbes
@ 2026-10-29 22:04 ` Zack Rusin
2026-10-30 0:33 ` Maaz Mombasawala <maaz.mombasawala@broadcom.com>
1 sibling, 0 replies; 3+ messages in thread
From: Zack Rusin @ 2026-10-29 22:04 UTC (permalink / raw)
To: Ian Forbes; +Cc: dri-devel, bcm-kernel-feedback-list, maaz.mombasawala
[-- Attachment #1: Type: text/plain, Size: 12566 bytes --]
On Thu, Oct 29, 2026 at 12:54 PM Ian Forbes <ian.forbes@broadcom.com> wrote:
>
> The last vmwgfx internal use of this code was removed in commit
> 2e10cdc6e85d ("drm/vmwgfx: Remove explicit and broken vblank handling")
>
> The vmw_fence_event ioctl was introduced in commit
> 57c5ee79acba ("vmwgfx: Add fence events") which claimed it would be used
> by the xf86-video-vmware Xorg driver but the git history shows that it was
> never used in that driver; nor was it used by mesa.
>
> Remove this code as we've had a number of bug reports related to it.
>
> Signed-off-by: Ian Forbes <ian.forbes@broadcom.com>
> ---
> drivers/gpu/drm/vmwgfx/vmwgfx_fence.c | 241 +-------------------------
> drivers/gpu/drm/vmwgfx/vmwgfx_fence.h | 6 -
> 2 files changed, 1 insertion(+), 246 deletions(-)
>
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
> index 384c6736cf6b..004ed060cf54 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.c
> @@ -23,27 +23,6 @@ struct vmw_user_fence {
> struct vmw_fence_obj fence;
> };
>
> -/**
> - * struct vmw_event_fence_action - fence callback that delivers a DRM event.
> - *
> - * @base: For use with dma_fence_add_callback(...)
> - * @event: A pointer to the pending event.
> - * @dev: Pointer to a struct drm_device so we can access the event stuff.
> - * @tv_sec: If non-null, the variable pointed to will be assigned
> - * current time tv_sec val when the fence signals.
> - * @tv_usec: Must be set if @tv_sec is set, and the variable pointed to will
> - * be assigned the current time tv_usec val when the fence signals.
> - */
> -struct vmw_event_fence_action {
> - struct dma_fence_cb base;
> -
> - struct drm_pending_event *event;
> - struct drm_device *dev;
> -
> - uint32_t *tv_sec;
> - uint32_t *tv_usec;
> -};
> -
> static struct vmw_fence_manager *
> fman_from_fence(struct vmw_fence_obj *fence)
> {
> @@ -524,226 +503,8 @@ int vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data,
> arg->handle);
> }
>
> -/**
> - * vmw_event_fence_action_seq_passed
> - *
> - * @f: The struct dma_fence which provides timestamp for the action event
> - * @cb: The struct dma_fence_cb callback for the action event.
> - *
> - * This function is called when the seqno of the fence has passed
> - * and it is always called from atomic context.
> - * It queues the event on the submitter's event list.
> - */
> -static void vmw_event_fence_action_seq_passed(struct dma_fence *f,
> - struct dma_fence_cb *cb)
> -{
> - struct vmw_event_fence_action *eaction =
> - container_of(cb, struct vmw_event_fence_action, base);
> - struct drm_device *dev = eaction->dev;
> - struct drm_pending_event *event = eaction->event;
> -
> - if (unlikely(event == NULL))
> - return;
> -
> - spin_lock_irq(&dev->event_lock);
> -
> - if (likely(eaction->tv_sec != NULL)) {
> - struct timespec64 ts;
> -
> - ts = ktime_to_timespec64(f->timestamp);
> - /* monotonic time, so no y2038 overflow */
> - *eaction->tv_sec = ts.tv_sec;
> - *eaction->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
> - }
> -
> - drm_send_event_locked(dev, eaction->event);
> - eaction->event = NULL;
> - spin_unlock_irq(&dev->event_lock);
> - dma_fence_put(f);
> - kfree(eaction);
> -}
> -
> -/**
> - * vmw_event_fence_action_queue - Post an event for sending when a fence
> - * object seqno has passed.
> - *
> - * @file_priv: The file connection on which the event should be posted.
> - * @fence: The fence object on which to post the event.
> - * @event: Event to be posted. This event should've been alloced
> - * using k[mz]alloc, and should've been completely initialized.
> - * @tv_sec: If non-null, the variable pointed to will be assigned
> - * current time tv_sec val when the fence signals.
> - * @tv_usec: Must be set if @tv_sec is set, and the variable pointed to will
> - * be assigned the current time tv_usec val when the fence signals.
> - * @interruptible: Interruptible waits if possible.
> - *
> - * As a side effect, the object pointed to by @event may have been
> - * freed when this function returns. If this function returns with
> - * an error code, the caller needs to free that object.
> - */
> -
> -int vmw_event_fence_action_queue(struct drm_file *file_priv,
> - struct vmw_fence_obj *fence,
> - struct drm_pending_event *event,
> - uint32_t *tv_sec,
> - uint32_t *tv_usec,
> - bool interruptible)
> -{
> - struct vmw_event_fence_action *eaction;
> - struct vmw_fence_manager *fman = fman_from_fence(fence);
> -
> - eaction = kzalloc_obj(*eaction);
> - if (unlikely(!eaction))
> - return -ENOMEM;
> -
> - eaction->event = event;
> - eaction->dev = &fman->dev_priv->drm;
> - eaction->tv_sec = tv_sec;
> - eaction->tv_usec = tv_usec;
> -
> - vmw_fence_obj_reference(fence); // Dropped in CB
> - if (dma_fence_add_callback(&fence->base, &eaction->base,
> - vmw_event_fence_action_seq_passed) < 0)
> - vmw_event_fence_action_seq_passed(&fence->base, &eaction->base);
> - return 0;
> -}
> -
> -struct vmw_event_fence_pending {
> - struct drm_pending_event base;
> - struct drm_vmw_event_fence event;
> -};
> -
> -static int vmw_event_fence_action_create(struct drm_file *file_priv,
> - struct vmw_fence_obj *fence,
> - uint32_t flags,
> - uint64_t user_data,
> - bool interruptible)
> -{
> - struct vmw_event_fence_pending *event;
> - struct vmw_fence_manager *fman = fman_from_fence(fence);
> - struct drm_device *dev = &fman->dev_priv->drm;
> - int ret;
> -
> - event = kzalloc_obj(*event);
> - if (unlikely(!event)) {
> - DRM_ERROR("Failed to allocate an event.\n");
> - ret = -ENOMEM;
> - goto out_no_space;
> - }
> -
> - event->event.base.type = DRM_VMW_EVENT_FENCE_SIGNALED;
> - event->event.base.length = sizeof(event->event);
> - event->event.user_data = user_data;
> -
> - ret = drm_event_reserve_init(dev, file_priv, &event->base, &event->event.base);
> -
> - if (unlikely(ret != 0)) {
> - DRM_ERROR("Failed to allocate event space for this file.\n");
> - kfree(event);
> - goto out_no_space;
> - }
> -
> - if (flags & DRM_VMW_FE_FLAG_REQ_TIME)
> - ret = vmw_event_fence_action_queue(file_priv, fence,
> - &event->base,
> - &event->event.tv_sec,
> - &event->event.tv_usec,
> - interruptible);
> - else
> - ret = vmw_event_fence_action_queue(file_priv, fence,
> - &event->base,
> - NULL,
> - NULL,
> - interruptible);
> - if (ret != 0)
> - goto out_no_queue;
> -
> - return 0;
> -
> -out_no_queue:
> - drm_event_cancel_free(dev, &event->base);
> -out_no_space:
> - return ret;
> -}
> -
> int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
> struct drm_file *file_priv)
> {
> - struct vmw_private *dev_priv = vmw_priv(dev);
> - struct drm_vmw_fence_event_arg *arg =
> - (struct drm_vmw_fence_event_arg *) data;
> - struct vmw_fence_obj *fence = NULL;
> - struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
> - struct ttm_object_file *tfile = vmw_fp->tfile;
> - struct drm_vmw_fence_rep __user *user_fence_rep =
> - (struct drm_vmw_fence_rep __user *)(unsigned long)
> - arg->fence_rep;
> - uint32_t handle;
> - int ret;
> -
> - /*
> - * Look up an existing fence object,
> - * and if user-space wants a new reference,
> - * add one.
> - */
> - if (arg->handle) {
> - struct ttm_base_object *base =
> - vmw_fence_obj_lookup(tfile, arg->handle);
> -
> - if (IS_ERR(base))
> - return PTR_ERR(base);
> -
> - fence = &(container_of(base, struct vmw_user_fence,
> - base)->fence);
> - (void) vmw_fence_obj_reference(fence);
> -
> - if (user_fence_rep != NULL) {
> - ret = ttm_ref_object_add(vmw_fp->tfile, base,
> - NULL, false);
> - if (unlikely(ret != 0)) {
> - DRM_ERROR("Failed to reference a fence "
> - "object.\n");
> - goto out_no_ref_obj;
> - }
> - handle = base->handle;
> - }
> - ttm_base_object_unref(&base);
> - }
> -
> - /*
> - * Create a new fence object.
> - */
> - if (!fence) {
> - ret = vmw_execbuf_fence_commands(file_priv, dev_priv,
> - &fence,
> - (user_fence_rep) ?
> - &handle : NULL);
> - if (unlikely(ret != 0)) {
> - DRM_ERROR("Fence event failed to create fence.\n");
> - return ret;
> - }
> - }
> -
> - BUG_ON(fence == NULL);
> -
> - ret = vmw_event_fence_action_create(file_priv, fence,
> - arg->flags,
> - arg->user_data,
> - true);
> - if (unlikely(ret != 0)) {
> - if (ret != -ERESTARTSYS)
> - DRM_ERROR("Failed to attach event to fence.\n");
> - goto out_no_create;
> - }
> -
> - vmw_execbuf_copy_fence_user(dev_priv, vmw_fp, 0, user_fence_rep, fence,
> - handle, -1);
> - vmw_fence_obj_unreference(&fence);
> - return 0;
> -out_no_create:
> - if (user_fence_rep != NULL)
> - ttm_ref_object_base_unref(tfile, handle);
> -out_no_ref_obj:
> - vmw_fence_obj_unreference(&fence);
> - return ret;
> + return -ENOTTY; // Never Used
> }
> diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
> index e897cccae1ae..24d7b279ca4b 100644
> --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
> +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fence.h
> @@ -101,10 +101,4 @@ extern int vmw_fence_obj_unref_ioctl(struct drm_device *dev, void *data,
> struct drm_file *file_priv);
> extern int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
> struct drm_file *file_priv);
> -extern int vmw_event_fence_action_queue(struct drm_file *filee_priv,
> - struct vmw_fence_obj *fence,
> - struct drm_pending_event *event,
> - uint32_t *tv_sec,
> - uint32_t *tv_usec,
> - bool interruptible);
> #endif /* _VMWGFX_FENCE_H_ */
> --
> 2.56.0
>
Yea, that's probably a good idea. Unused code is so hard to maintain
in the llm age.
Reviewed-by: Zack Rusin <zack.rusin@broadcom.com>
z
[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 5414 bytes --]
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] drm/vmwgfx: Remove fence event code
2026-10-29 16:54 [PATCH] drm/vmwgfx: Remove fence event code Ian Forbes
2026-10-29 22:04 ` Zack Rusin
@ 2026-10-30 0:33 ` Maaz Mombasawala <maaz.mombasawala@broadcom.com>
1 sibling, 0 replies; 3+ messages in thread
From: Maaz Mombasawala <maaz.mombasawala@broadcom.com> @ 2026-10-30 0:33 UTC (permalink / raw)
To: Ian Forbes, dri-devel; +Cc: bcm-kernel-feedback-list, zack.rusin
LGTM!
Reviewed-by: Maaz Mombasawala <maaz.mombasawala@broadcom.com>
--
Maaz Mombasawala <maaz.mombasawala@broadcom.com>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-30 0:32 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-29 16:54 [PATCH] drm/vmwgfx: Remove fence event code Ian Forbes
2026-10-29 22:04 ` Zack Rusin
2026-10-30 0:33 ` Maaz Mombasawala <maaz.mombasawala@broadcom.com>
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.