On Mon 24-04-17 19:41:32, Andrey Ryabinin wrote: > Some direct IO write fs hooks call invalidate_inode_pages2[_range]() > conditionally iff mapping->nrpages is not zero. This can't be right, > because invalidate_inode_pages2[_ragne]() also invalidate data in > the cleancache via cleancache_invalidate_inode() call. > So if page cache is empty but there is some data in the cleancache, > buffered read after direct IO write would get stale data from > the cleancache. > > Also it doesn't feel right to check only for ->nrpages because > invalidate_inode_pages2[_range] invalidates exceptional entries as well. > > Fix this by calling invalidate_inode_pages2[_range]() regardless of nrpages > state. > > Note: nfs,cifs,9p doesn't need similar fix because the never call > cleancache_get_page() (nor directly, nor via mpage_readpage[s]()), so they > are not affected by this bug. > > Fixes: c515e1fd361c ("mm/fs: add hooks to support cleancache") > Signed-off-by: Andrey Ryabinin <aryabinin@xxxxxxxxxxxxx> > Acked-by: Konrad Rzeszutek Wilk <konrad.wilk@xxxxxxxxxx> > Cc: <stable@xxxxxxxxxxxxxxx> OK, looks good. You can add: Reviewed-by: Jan Kara <jack@xxxxxxx> Honza > --- > fs/iomap.c | 18 ++++++++---------- > mm/filemap.c | 26 +++++++++++--------------- > 2 files changed, 19 insertions(+), 25 deletions(-) > > diff --git a/fs/iomap.c b/fs/iomap.c > index cdeed39..f6a6013 100644 > --- a/fs/iomap.c > +++ b/fs/iomap.c > @@ -881,16 +881,14 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter, > flags |= IOMAP_WRITE; > } > > - if (mapping->nrpages) { > - ret = filemap_write_and_wait_range(mapping, start, end); > - if (ret) > - goto out_free_dio; > + ret = filemap_write_and_wait_range(mapping, start, end); > + if (ret) > + goto out_free_dio; > > - ret = invalidate_inode_pages2_range(mapping, > - start >> PAGE_SHIFT, end >> PAGE_SHIFT); > - WARN_ON_ONCE(ret); > - ret = 0; > - } > + ret = invalidate_inode_pages2_range(mapping, > + start >> PAGE_SHIFT, end >> PAGE_SHIFT); > + WARN_ON_ONCE(ret); > + ret = 0; > > inode_dio_begin(inode); > > @@ -945,7 +943,7 @@ iomap_dio_rw(struct kiocb *iocb, struct iov_iter *iter, > * one is a pretty crazy thing to do, so we don't support it 100%. If > * this invalidation fails, tough, the write still worked... > */ > - if (iov_iter_rw(iter) == WRITE && mapping->nrpages) { > + if (iov_iter_rw(iter) == WRITE) { > int err = invalidate_inode_pages2_range(mapping, > start >> PAGE_SHIFT, end >> PAGE_SHIFT); > WARN_ON_ONCE(err); > diff --git a/mm/filemap.c b/mm/filemap.c > index 9eab40e..b7b973b 100644 > --- a/mm/filemap.c > +++ b/mm/filemap.c > @@ -2720,18 +2720,16 @@ generic_file_direct_write(struct kiocb *iocb, struct iov_iter *from) > * about to write. We do this *before* the write so that we can return > * without clobbering -EIOCBQUEUED from ->direct_IO(). > */ > - if (mapping->nrpages) { > - written = invalidate_inode_pages2_range(mapping, > + written = invalidate_inode_pages2_range(mapping, > pos >> PAGE_SHIFT, end); > - /* > - * If a page can not be invalidated, return 0 to fall back > - * to buffered write. > - */ > - if (written) { > - if (written == -EBUSY) > - return 0; > - goto out; > - } > + /* > + * If a page can not be invalidated, return 0 to fall back > + * to buffered write. > + */ > + if (written) { > + if (written == -EBUSY) > + return 0; > + goto out; > } > > written = mapping->a_ops->direct_IO(iocb, from); > @@ -2744,10 +2742,8 @@ generic_file_direct_write(struct kiocb *iocb, struct iov_iter *from) > * so we don't support it 100%. If this invalidation > * fails, tough, the write still worked... > */ > - if (mapping->nrpages) { > - invalidate_inode_pages2_range(mapping, > - pos >> PAGE_SHIFT, end); > - } > + invalidate_inode_pages2_range(mapping, > + pos >> PAGE_SHIFT, end); > > if (written > 0) { > pos += written; > -- > 2.10.2 > -- Jan Kara <jack@xxxxxxxx> SUSE Labs, CR