Re: [PATCH v7 06/22] Replace XIP read and write with DAX I/O

From: Jan Kara
Date: Wed Apr 09 2014 - 16:55:41 EST


On Wed 09-04-14 11:19:08, Matthew Wilcox wrote:
> On Wed, Apr 09, 2014 at 11:14:50AM +0200, Jan Kara wrote:
> > On Tue 08-04-14 16:21:02, Matthew Wilcox wrote:
> > > On Tue, Apr 08, 2014 at 07:56:00PM +0200, Jan Kara wrote:
> > > > > +static void dax_new_buf(void *addr, unsigned size, unsigned first,
> > > > > + loff_t offset, loff_t end, int rw)
> > > > > +{
> > > > > + loff_t final = end - offset + first; /* The final byte of the buffer */
> > > > > + if (rw != WRITE) {
> > > > > + memset(addr, 0, size);
> > > > > + return;
> > > > > + }
> > > > It seems counterintuitive to zero out "on-disk" blocks (it seems you'd do
> > > > this for unwritten blocks) when reading from them. Presumably it could also
> > > > have undesired effects on endurance of persistent memory. Instead I'd expect
> > > > that you simply zero out user provided buffer the same way as you do it for
> > > > holes.
> > >
> > > I think we have to zero it here, because the second time we call
> > > get_block() for a given block, it won't be BH_New any more, so we won't
> > > know that it's supposed to be zeroed.
> > But how can you have BH_New buffer when you didn't ask get_blocks() to
> > create any block? That would be a bug in the get_blocks() implementation...
> > Or am I missing something?
>
> Oh ... right. So just to be clear, we're looking at the case where
> we're doing a read of a filesystem block which is BH_Unwritten, but
> isn't a hole ... so it's been allocated on storage and not yet written.
> That's already treated as a hole:
>
> if (rw == WRITE) {
> ...
> } else {
> hole = !buffer_written(bh);
> }
>
> and dax_new_buf is only called in the !hole case.
Ah, my bad. But then dax_new_buf() won't ever be called for rw != WRITE.
get_blocks() cannot ever return BH_New buffer when 'create' argument was 0.

> > > > > + if ((flags & DIO_LOCKING) && (rw == READ)) {
> > > > > + struct address_space *mapping = inode->i_mapping;
> > > > > + mutex_lock(&inode->i_mutex);
> > > > > + retval = filemap_write_and_wait_range(mapping, offset, end - 1);
> > > > > + if (retval) {
> > > > > + mutex_unlock(&inode->i_mutex);
> > > > > + goto out;
> > > > > + }
> > > > Is there a reason for this? I'd assume DAX has no pages in pagecache...
> > >
> > > There will be pages in the page cache for holes that we page faulted on.
> > > They must go! :-)
> > Well, but this will only writeback dirty pages and if I read the code
> > correctly those pages will never be dirty since dax_mkwrite() will replace
> > them. Or am I missing something?
>
> In addition to writing back dirty pages, filemap_write_and_wait_range()
> will evict clean pages. Unintuitive, I know, but it matches what the
> direct I/O path does. Plus, if we fall back to buffered I/O for holes
> (see above), then this will do the right thing at that time.
Ugh, I'm pretty certain filemap_write_and_wait_range() doesn't evict
anything ;). Direct IO path calls that function so that direct IO read
after buffered write returns the written data. In that case we don't evict
anything from page cache because direct IO read doesn't invalidate any
information we have cached. Only direct IO write does that and for that we
call invalidate_inode_pages2_range() after writing the pages. So I maintain
that what you do doesn't make sense to me. You might need to do some
invalidation of hole pages. But note that generic_file_direct_write() does
that for you and even though that isn't serialized in any way with page
faults which can instantiate the hole pages again, things should work out
fine for you since that function also invalidates the range again after
->direct_IO callback is done. So AFAICT you don't have to do anything
except writing some nice comment about this ;).

Honza
--
Jan Kara <jack@xxxxxxx>
SUSE Labs, CR
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/