Re: [PATCH 2/2] iomap: zero cached pages over unwritten extents on zero range

Christoph Hellwig
2020-10-27T18:15:57Z

On Tue, Oct 20, 2020 at 12:21:50PM -0400, Brian Foster wrote:
> Ugh, so the above doesn't quite describe historical behavior.
> block_truncate_page() converts an unwritten block if a page exists
> (dirty or not), but bails out if a page doesn't exist. We could still do
> the above, but if we wanted something more intelligent I think we need
> to check for a page before we get the mapping to know whether we can
> safely skip an unwritten block or need to write over it. Otherwise if we
> check for a page within the actor, we have no way of knowing whether
> there was a (possibly dirty) page that had been written back and/or
> reclaimed since ->iomap_begin(). If we check for the page first, I think
> that the iolock/mmaplock in the truncate path ensures that a page can't
> be added before we complete. We might be able to take that further and
> check for a dirty || writeback page, but that might be safer as a
> separate patch. See the (compile tested only) diff below for an idea of
> what I was thinking.

The idea looks reasonable, but a few comment below:

> +struct iomap_trunc_priv {
> + bool *did_zero;

I don't think there is any point on using a pointer here, when we
can trivially copy out the scalar value.

> + bool has_page;

The naming of this flag really confuses me. Maybe has_data or
in_pagecache might be better options?

> +static loff_t
> +iomap_truncate_page_actor(struct inode *inode, loff_t pos, loff_t count,
> + void *data, struct iomap *iomap, struct iomap *srcmap)
> +{
> + struct iomap_trunc_priv *priv = data;
> + unsigned offset;
> + int status;
> +
> + if (srcmap->type == IOMAP_HOLE)
> + return count;
> + if (srcmap->type == IOMAP_UNWRITTEN && !priv->has_page)
> + return count;

Maybe add a comment here to explain why priv->has_page matters?

> +
> + offset = offset_in_page(pos);

I'd move this on the initialization line.

> + ret = iomap_apply(inode, pos, blocksize - off, IOMAP_ZERO, ops, &priv,
> + iomap_truncate_page_actor);
> + if (ret <= 0)
> + return ret;

The check could just be < 0 and would be a little more obvious.