# zx_pager_query_dirty_ranges

## Summary

Query contiguous ranges of dirty pages in a pager owned VMO.

## Declaration

    #include <zircon/syscalls.h>

    zx_status_t zx_pager_query_dirty_ranges(zx_handle_t pager,
                                            zx_handle_t pager_vmo,
                                            uint64_t offset,
                                            uint64_t length,
                                            void* buffer,
                                            size_t buffer_size,
                                            size_t* actual,
                                            size_t* avail);

## Description

Queries *pager_vmo* for contiguous runs of pages in the range \[*offset* , *offset* + *length* ) that
are dirty, i.e. have outstanding modifications that have not been written back to the pager source.
The *pager_vmo* must have previously been created from the *pager* by [`zx_pager_create_vmo()`](https://fuchsia.dev/reference/syscalls/pager_create_vmo).
*offset* and *length* need not be page aligned, but they will be rounded to page boundaries when
performing the query.

*buffer* should point to an array of `zx_vmo_dirty_range_t` struct that will hold the result of the
query, and *buffer_size* should accommodate the array.

    typedef struct zx_vmo_dirty_range {
      // Represents the range [offset, offset + length).
      uint64_t offset;
      uint64_t length;
      // Any options applicable to the range.
      // ZX_VMO_DIRTY_RANGE_IS_ZERO indicates that the range contains all zeros.
      uint64_t options;
    } zx_vmo_dirty_range_t;

*actual* is an optional pointer to return the number of dirty ranges that were written to *buffer*.

*avail* is an optional pointer to return the number of dirty ranges that are available to read. If
*buffer* is insufficiently large, *avail* will be larger than *actual*.

Upon success, *actual* will contain the number of dirty ranges that were copied out to *buffer* .
The number of dirty ranges that are copied out to *buffer* is constrained by *buffer_size* , i.e. it
is possible for there to exist more dirty ranges in \[*offset* , *offset* + *length* ) that could not
be accommodated in *buffer* . The caller can assume than any range that had been made dirty prior to
making the call will either be contained in *buffer* , or will have a start offset strictly greater
than the last range in *buffer* . Therefore, the caller can advance *offset* and make another query
to discover further dirty ranges, until *avail* is zero.

Sample user code that wants to query all dirty ranges in a VMO might look like this:

      zx_vmo_dirty_range_t ranges[5];
      size_t actual = 0;
      size_t avail = 0;
      uint64_t start = 0;
      uint64_t len = vmo_size;

      while (len > 0) {
        zx_status_t st = zx_pager_query_dirty_ranges(pager, vmo, start, len,
                                                     &ranges[0],
                                                     5 * sizeof(zx_vmo_dirty_range_t),
                                                     &actual, &avail);
        // Process the |ranges| returned as needed.
        ProcessDirtyRanges(&ranges[0], actual);

        // We've read all the dirty ranges that existed before the query.
        if (actual == avail) {
          break;
        }
        // We used up the entire |ranges| buffer, but there are more dirty ranges to be read.
        // Advance start beyond the last dirty range found.
        uint64_t new_start = ranges[4].offset + ranges[4].length;
        len -= (new_start - start);
        start = new_start;
      }

## Rights

*pager* must be of type `ZX_OBJ_TYPE_PAGER` and have `ZX_RIGHT_MANAGE_VMO`.

*pager_vmo* must be of type `ZX_OBJ_TYPE_VMO` and have `ZX_RIGHT_READ`.

## Return value

`zx_pager_query_dirty_ranges()` returns `ZX_OK` on success. In the event of failure, a negative
error value is returned.

## Errors

`ZX_ERR_BAD_HANDLE` *pager* or *pager_vmo* is not a valid handle.

`ZX_ERR_WRONG_TYPE` *pager* is not a pager handle, or *pager_vmo* is not a VMO handle.

`ZX_ERR_ACCESS_DENIED` *pager* does not have `ZX_RIGHT_MANAGE_VMO` or *pager_vmo* does not have
`ZX_RIGHT_READ`.

`ZX_ERR_INVALID_ARGS` *pager_vmo* is not a VMO created from *pager* , or *buffer* is an invalid
pointer.

`ZX_ERR_OUT_OF_RANGE` The specified range in *pager_vmo* is invalid.

## See also

- [`zx_pager_create_vmo()`](https://fuchsia.dev/reference/syscalls/pager_create_vmo)
- [`zx_pager_detach_vmo()`](https://fuchsia.dev/reference/syscalls/pager_detach_vmo)
- [`zx_pager_op_range()`](https://fuchsia.dev/reference/syscalls/pager_op_range)
- [`zx_pager_query_vmo_stats()`](https://fuchsia.dev/reference/syscalls/pager_query_vmo_stats)
- [`zx_pager_supply_pages()`](https://fuchsia.dev/reference/syscalls/pager_supply_pages)