bcachefs: fix up wonky error handling in bch2_seek_pagecache_hole()
authorBrian Foster <bfoster@redhat.com>
Mon, 14 Aug 2023 14:49:42 +0000 (10:49 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:10:11 +0000 (17:10 -0400)
The folio_hole_offset() helper returns a mix of bool and int types.
The latter is to support a possible -EAGAIN error code when using
nonblocking locks. This is not only confusing, but the only caller
also essentially ignores errors outside of stopping the range
iteration. This means an -EAGAIN error can't return directly from
folio_hole_offset() and may be lost via bch2_clamp_data_hole().

Fix up the error handling and make it more readable.
__filemap_get_folio() returns -ENOENT instead of NULL when no folio
exists, so reuse the same error code in folio_hole_offset(). Fix up
bch2_seek_pagecache_hole() to return the current offset on -ENOENT,
but otherwise return unexpected error code up to the caller.

Signed-off-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/fs-io-pagecache.c

index 2c1ef13d9bcdbb41586c25b6367be344ff0edeee..1e60eead29815ccb0dad99b07c4df1ee64055801 100644 (file)
@@ -698,20 +698,26 @@ loff_t bch2_seek_pagecache_data(struct inode *vinode,
        return end_offset;
 }
 
+/*
+ * Search for a hole in a folio.
+ *
+ * The filemap layer returns -ENOENT if no folio exists, so reuse the same error
+ * code to indicate a pagecache hole exists at the returned offset. Otherwise
+ * return 0 if the folio is filled with data, or an error code. This function
+ * can return -EAGAIN if nonblock is specified.
+ */
 static int folio_hole_offset(struct address_space *mapping, loff_t *offset,
                              unsigned min_replicas, bool nonblock)
 {
        struct folio *folio;
        struct bch_folio *s;
        unsigned i, sectors;
-       bool ret = true;
+       int ret = -ENOENT;
 
        folio = __filemap_get_folio(mapping, *offset >> PAGE_SHIFT,
                                    FGP_LOCK|(nonblock ? FGP_NOWAIT : 0), 0);
-       if (folio == ERR_PTR(-EAGAIN))
-               return -EAGAIN;
-       if (IS_ERR_OR_NULL(folio))
-               return true;
+       if (IS_ERR(folio))
+               return PTR_ERR(folio);
 
        s = bch2_folio(folio);
        if (!s)
@@ -727,7 +733,7 @@ static int folio_hole_offset(struct address_space *mapping, loff_t *offset,
                }
 
        *offset = folio_end_pos(folio);
-       ret = false;
+       ret = 0;
 unlock:
        folio_unlock(folio);
        folio_put(folio);
@@ -742,11 +748,13 @@ loff_t bch2_seek_pagecache_hole(struct inode *vinode,
 {
        struct address_space *mapping = vinode->i_mapping;
        loff_t offset = start_offset;
+       loff_t ret = 0;
 
-       while (offset < end_offset &&
-              !folio_hole_offset(mapping, &offset, min_replicas, nonblock))
-               ;
+       while (!ret && offset < end_offset)
+               ret = folio_hole_offset(mapping, &offset, min_replicas, nonblock);
 
+       if (ret && ret != -ENOENT)
+               return ret;
        return min(offset, end_offset);
 }