Message ID | 62950460a9e78804df28c548327d779a8d53243f.1686395560.git.ritesh.list@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | iomap: Add support for per-block dirty state to improve write performance | expand |
On Sat, Jun 10, 2023 at 05:09:05PM +0530, Ritesh Harjani (IBM) wrote: > This patch factors iomap_write_delalloc_punch() function out. This function > is resposible for actual punch out operation. > The reason for doing this is, to avoid deep indentation when we bring punch-out > of individual non-dirty blocks within a dirty folio in a later patch > (which adds per-block dirty status handling to iomap) to avoid delalloc block > leak. A bunch of overly long lines in the commit message here, but otherwise this looks good: Reviewed-by: Christoph Hellwig <hch@lst.de>
Christoph Hellwig <hch@infradead.org> writes: > On Sat, Jun 10, 2023 at 05:09:05PM +0530, Ritesh Harjani (IBM) wrote: >> This patch factors iomap_write_delalloc_punch() function out. This function >> is resposible for actual punch out operation. >> The reason for doing this is, to avoid deep indentation when we bring punch-out >> of individual non-dirty blocks within a dirty folio in a later patch >> (which adds per-block dirty status handling to iomap) to avoid delalloc block >> leak. > > A bunch of overly long lines in the commit message here, > but otherwise this looks good: Sure. Will shorten those in next revision (considering we might need it for some minor changes in patch-6) > > Reviewed-by: Christoph Hellwig <hch@lst.de> Thanks! -ritesh
On Sat, Jun 10, 2023 at 05:09:05PM +0530, Ritesh Harjani (IBM) wrote: > +static int iomap_write_delalloc_punch(struct inode *inode, struct folio *folio, > + loff_t *punch_start_byte, loff_t start_byte, loff_t end_byte, > + int (*punch)(struct inode *inode, loff_t offset, loff_t length)) I can't help but feel that a typedef iomap_punch_t(struct inode *, loff_t offset, loff_t length); would make all of this easier to read. > + /* > + * Make sure the next punch start is correctly bound to > + * the end of this data range, not the end of the folio. > + */ > + *punch_start_byte = min_t(loff_t, end_byte, > + folio_next_index(folio) << PAGE_SHIFT); *punch_start_byte = min(end_byte, folio_pos(folio) + folio_size(folio));
Minor nit: > +static int iomap_write_delalloc_punch(struct inode *inode, struct folio *folio, > + loff_t *punch_start_byte, loff_t start_byte, loff_t end_byte, > + int (*punch)(struct inode *inode, loff_t offset, loff_t length)) > +{ > + int ret = 0; > + > + if (!folio_test_dirty(folio)) > + return ret; Either this could be changed to `goto out` OR > + > + /* if dirty, punch up to offset */ > + if (start_byte > *punch_start_byte) { > + ret = punch(inode, *punch_start_byte, > + start_byte - *punch_start_byte); > + if (ret) > + goto out; This could be changed to `return ret` and we could get rid of the `out` label. > + } > + /* > + * Make sure the next punch start is correctly bound to > + * the end of this data range, not the end of the folio. > + */ > + *punch_start_byte = min_t(loff_t, end_byte, > + folio_next_index(folio) << PAGE_SHIFT); > + > +out: > + return ret; > +} > +
Matthew Wilcox <willy@infradead.org> writes: > On Sat, Jun 10, 2023 at 05:09:05PM +0530, Ritesh Harjani (IBM) wrote: >> +static int iomap_write_delalloc_punch(struct inode *inode, struct folio *folio, >> + loff_t *punch_start_byte, loff_t start_byte, loff_t end_byte, >> + int (*punch)(struct inode *inode, loff_t offset, loff_t length)) > > I can't help but feel that a > > typedef iomap_punch_t(struct inode *, loff_t offset, loff_t length); > > would make all of this easier to read. > Sure. Make sense. >> + /* >> + * Make sure the next punch start is correctly bound to >> + * the end of this data range, not the end of the folio. >> + */ >> + *punch_start_byte = min_t(loff_t, end_byte, >> + folio_next_index(folio) << PAGE_SHIFT); > > *punch_start_byte = min(end_byte, folio_pos(folio) + folio_size(folio)); Current code was also correct only. But I guess this just avoids min_t/loff_t thing. No other reason right? -ritesh
On Mon, Jun 12, 2023 at 07:33:29PM +0530, Ritesh Harjani wrote: > >> + *punch_start_byte = min_t(loff_t, end_byte, > >> + folio_next_index(folio) << PAGE_SHIFT); > > > > *punch_start_byte = min(end_byte, folio_pos(folio) + folio_size(folio)); > > Current code was also correct only. But I guess this just avoids > min_t/loff_t thing. No other reason right? Actually, it's buggy on 32-bit platforms. folio_next_index returns an unsigned long (32 bit), which is shifted by PAGE_SHIFT, losing the top bits, then cast to an loff_t. folio_pos() does this correctly.
Pankaj Raghav <p.raghav@samsung.com> writes: > Minor nit: > >> +static int iomap_write_delalloc_punch(struct inode *inode, struct folio *folio, >> + loff_t *punch_start_byte, loff_t start_byte, loff_t end_byte, >> + int (*punch)(struct inode *inode, loff_t offset, loff_t length)) >> +{ >> + int ret = 0; >> + >> + if (!folio_test_dirty(folio)) >> + return ret; > Either this could be changed to `goto out` > > OR > >> + >> + /* if dirty, punch up to offset */ >> + if (start_byte > *punch_start_byte) { >> + ret = punch(inode, *punch_start_byte, >> + start_byte - *punch_start_byte); >> + if (ret) >> + goto out; > > This could be changed to `return ret` and we could get rid of the `out` > label. Sure, thanks Pankaj. I noted that too. Since there is nothing in the out label. So mostly will simply return ret. Will fix it in the next rev. -ritesh
diff --git a/fs/iomap/buffered-io.c b/fs/iomap/buffered-io.c index 206808f6e818..1261f26479af 100644 --- a/fs/iomap/buffered-io.c +++ b/fs/iomap/buffered-io.c @@ -888,6 +888,33 @@ iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *i, } EXPORT_SYMBOL_GPL(iomap_file_buffered_write); +static int iomap_write_delalloc_punch(struct inode *inode, struct folio *folio, + loff_t *punch_start_byte, loff_t start_byte, loff_t end_byte, + int (*punch)(struct inode *inode, loff_t offset, loff_t length)) +{ + int ret = 0; + + if (!folio_test_dirty(folio)) + return ret; + + /* if dirty, punch up to offset */ + if (start_byte > *punch_start_byte) { + ret = punch(inode, *punch_start_byte, + start_byte - *punch_start_byte); + if (ret) + goto out; + } + /* + * Make sure the next punch start is correctly bound to + * the end of this data range, not the end of the folio. + */ + *punch_start_byte = min_t(loff_t, end_byte, + folio_next_index(folio) << PAGE_SHIFT); + +out: + return ret; +} + /* * Scan the data range passed to us for dirty page cache folios. If we find a * dirty folio, punch out the preceeding range and update the offset from which @@ -911,6 +938,7 @@ static int iomap_write_delalloc_scan(struct inode *inode, { while (start_byte < end_byte) { struct folio *folio; + int ret; /* grab locked page */ folio = filemap_lock_folio(inode->i_mapping, @@ -921,26 +949,12 @@ static int iomap_write_delalloc_scan(struct inode *inode, continue; } - /* if dirty, punch up to offset */ - if (folio_test_dirty(folio)) { - if (start_byte > *punch_start_byte) { - int error; - - error = punch(inode, *punch_start_byte, - start_byte - *punch_start_byte); - if (error) { - folio_unlock(folio); - folio_put(folio); - return error; - } - } - - /* - * Make sure the next punch start is correctly bound to - * the end of this data range, not the end of the folio. - */ - *punch_start_byte = min_t(loff_t, end_byte, - folio_next_index(folio) << PAGE_SHIFT); + ret = iomap_write_delalloc_punch(inode, folio, punch_start_byte, + start_byte, end_byte, punch); + if (ret) { + folio_unlock(folio); + folio_put(folio); + return ret; } /* move offset to start of next folio in range */