]> git.sesse.net Git - bcachefs-tools-debian/blobdiff - libbcachefs/fs-io.c
Update bcachefs sources to 5b8c4a1366 bcachefs: bcachefs_metadata_version_deleted_inodes
[bcachefs-tools-debian] / libbcachefs / fs-io.c
index 6b691b2b52afeb70703dd5387ee670e2c2931580..d433f4d5662da9fd8991823ca2c37d1c0aae3082 100644 (file)
@@ -35,7 +35,7 @@
 
 #include <trace/events/writeback.h>
 
-static void bch2_clamp_data_hole(struct inode *, u64 *, u64 *, unsigned);
+static int bch2_clamp_data_hole(struct inode *, u64 *, u64 *, unsigned, bool);
 
 struct folio_vec {
        struct folio    *fv_folio;
@@ -3410,11 +3410,15 @@ static int __bchfs_fallocate(struct bch_inode_info *inode, int mode,
                }
 
                if (!(mode & FALLOC_FL_ZERO_RANGE)) {
-                       ret = drop_locks_do(&trans,
-                               (bch2_clamp_data_hole(&inode->v,
-                                                     &hole_start,
-                                                     &hole_end,
-                                                     opts.data_replicas), 0));
+                       if (bch2_clamp_data_hole(&inode->v,
+                                                &hole_start,
+                                                &hole_end,
+                                                opts.data_replicas, true))
+                               ret = drop_locks_do(&trans,
+                                       (bch2_clamp_data_hole(&inode->v,
+                                                             &hole_start,
+                                                             &hole_end,
+                                                             opts.data_replicas, false), 0));
                        bch2_btree_iter_set_pos(&iter, POS(iter.pos.inode, hole_start));
 
                        if (ret)
@@ -3714,7 +3718,8 @@ static int folio_data_offset(struct folio *folio, loff_t pos,
 static loff_t bch2_seek_pagecache_data(struct inode *vinode,
                                       loff_t start_offset,
                                       loff_t end_offset,
-                                      unsigned min_replicas)
+                                      unsigned min_replicas,
+                                      bool nonblock)
 {
        struct folio_batch fbatch;
        pgoff_t start_index     = start_offset >> PAGE_SHIFT;
@@ -3731,7 +3736,13 @@ static loff_t bch2_seek_pagecache_data(struct inode *vinode,
                for (i = 0; i < folio_batch_count(&fbatch); i++) {
                        struct folio *folio = fbatch.folios[i];
 
-                       folio_lock(folio);
+                       if (!nonblock) {
+                               folio_lock(folio);
+                       } else if (!folio_trylock(folio)) {
+                               folio_batch_release(&fbatch);
+                               return -EAGAIN;
+                       }
+
                        offset = folio_data_offset(folio,
                                        max(folio_pos(folio), start_offset),
                                        min_replicas);
@@ -3796,7 +3807,7 @@ err:
 
        if (next_data > offset)
                next_data = bch2_seek_pagecache_data(&inode->v,
-                                                    offset, next_data, 0);
+                                       offset, next_data, 0, false);
 
        if (next_data >= isize)
                return -ENXIO;
@@ -3804,18 +3815,24 @@ err:
        return vfs_setpos(file, next_data, MAX_LFS_FILESIZE);
 }
 
-static bool folio_hole_offset(struct address_space *mapping, loff_t *offset,
-                             unsigned min_replicas)
+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;
 
-       folio = filemap_lock_folio(mapping, *offset >> PAGE_SHIFT);
+       folio = __filemap_get_folio(mapping, *offset >> PAGE_SHIFT,
+                                   !nonblock ? FGP_LOCK : 0, 0);
        if (IS_ERR_OR_NULL(folio))
                return true;
 
+       if (nonblock && !folio_trylock(folio)) {
+               folio_put(folio);
+               return -EAGAIN;
+       }
+
        s = bch2_folio(folio);
        if (!s)
                goto unlock;
@@ -3833,37 +3850,51 @@ static bool folio_hole_offset(struct address_space *mapping, loff_t *offset,
        ret = false;
 unlock:
        folio_unlock(folio);
+       folio_put(folio);
        return ret;
 }
 
 static loff_t bch2_seek_pagecache_hole(struct inode *vinode,
                                       loff_t start_offset,
                                       loff_t end_offset,
-                                      unsigned min_replicas)
+                                      unsigned min_replicas,
+                                      bool nonblock)
 {
        struct address_space *mapping = vinode->i_mapping;
        loff_t offset = start_offset;
 
        while (offset < end_offset &&
-              !folio_hole_offset(mapping, &offset, min_replicas))
+              !folio_hole_offset(mapping, &offset, min_replicas, nonblock))
                ;
 
        return min(offset, end_offset);
 }
 
-static void bch2_clamp_data_hole(struct inode *inode,
-                                u64 *hole_start,
-                                u64 *hole_end,
-                                unsigned min_replicas)
+static int bch2_clamp_data_hole(struct inode *inode,
+                               u64 *hole_start,
+                               u64 *hole_end,
+                               unsigned min_replicas,
+                               bool nonblock)
 {
-       *hole_start = bch2_seek_pagecache_hole(inode,
-               *hole_start << 9, *hole_end << 9, min_replicas) >> 9;
+       loff_t ret;
+
+       ret = bch2_seek_pagecache_hole(inode,
+               *hole_start << 9, *hole_end << 9, min_replicas, nonblock) >> 9;
+       if (ret < 0)
+               return ret;
+
+       *hole_start = ret;
 
        if (*hole_start == *hole_end)
-               return;
+               return 0;
 
-       *hole_end = bch2_seek_pagecache_data(inode,
-               *hole_start << 9, *hole_end << 9, min_replicas) >> 9;
+       ret = bch2_seek_pagecache_data(inode,
+               *hole_start << 9, *hole_end << 9, min_replicas, nonblock) >> 9;
+       if (ret < 0)
+               return ret;
+
+       *hole_end = ret;
+       return 0;
 }
 
 static loff_t bch2_seek_hole(struct file *file, u64 offset)
@@ -3895,12 +3926,12 @@ retry:
                           BTREE_ITER_SLOTS, k, ret) {
                if (k.k->p.inode != inode->v.i_ino) {
                        next_hole = bch2_seek_pagecache_hole(&inode->v,
-                                       offset, MAX_LFS_FILESIZE, 0);
+                                       offset, MAX_LFS_FILESIZE, 0, false);
                        break;
                } else if (!bkey_extent_is_data(k.k)) {
                        next_hole = bch2_seek_pagecache_hole(&inode->v,
                                        max(offset, bkey_start_offset(k.k) << 9),
-                                       k.k->p.offset << 9, 0);
+                                       k.k->p.offset << 9, 0, false);
 
                        if (next_hole < k.k->p.offset << 9)
                                break;