Merge tag 'media/v6.8-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[linux-block.git] / block / bio.c
index 816d412c06e9b41ce13c3223a303fe5b6155156e..b9642a41f286e5bb52d841255aa9286c1449e83d 100644 (file)
@@ -944,7 +944,7 @@ bool bvec_try_merge_hw_page(struct request_queue *q, struct bio_vec *bv,
 
        if ((addr1 | mask) != (addr2 | mask))
                return false;
-       if (bv->bv_len + len > queue_max_segment_size(q))
+       if (len > queue_max_segment_size(q) - bv->bv_len)
                return false;
        return bvec_try_merge_page(bv, page, len, offset, same_page);
 }
@@ -966,10 +966,13 @@ int bio_add_hw_page(struct request_queue *q, struct bio *bio,
                struct page *page, unsigned int len, unsigned int offset,
                unsigned int max_sectors, bool *same_page)
 {
+       unsigned int max_size = max_sectors << SECTOR_SHIFT;
+
        if (WARN_ON_ONCE(bio_flagged(bio, BIO_CLONED)))
                return 0;
 
-       if (((bio->bi_iter.bi_size + len) >> SECTOR_SHIFT) > max_sectors)
+       len = min3(len, max_size, queue_max_segment_size(q));
+       if (len > max_size - bio->bi_iter.bi_size)
                return 0;
 
        if (bio->bi_vcnt > 0) {
@@ -1145,13 +1148,22 @@ EXPORT_SYMBOL(bio_add_folio);
 
 void __bio_release_pages(struct bio *bio, bool mark_dirty)
 {
-       struct bvec_iter_all iter_all;
-       struct bio_vec *bvec;
+       struct folio_iter fi;
 
-       bio_for_each_segment_all(bvec, bio, iter_all) {
-               if (mark_dirty && !PageCompound(bvec->bv_page))
-                       set_page_dirty_lock(bvec->bv_page);
-               bio_release_page(bio, bvec->bv_page);
+       bio_for_each_folio_all(fi, bio) {
+               struct page *page;
+               size_t done = 0;
+
+               if (mark_dirty) {
+                       folio_lock(fi.folio);
+                       folio_mark_dirty(fi.folio);
+                       folio_unlock(fi.folio);
+               }
+               page = folio_page(fi.folio, fi.offset / PAGE_SIZE);
+               do {
+                       bio_release_page(bio, page++);
+                       done += PAGE_SIZE;
+               } while (done < fi.length);
        }
 }
 EXPORT_SYMBOL_GPL(__bio_release_pages);
@@ -1439,18 +1451,12 @@ EXPORT_SYMBOL(bio_free_pages);
  * bio_set_pages_dirty() and bio_check_pages_dirty() are support functions
  * for performing direct-IO in BIOs.
  *
- * The problem is that we cannot run set_page_dirty() from interrupt context
+ * The problem is that we cannot run folio_mark_dirty() from interrupt context
  * because the required locks are not interrupt-safe.  So what we can do is to
  * mark the pages dirty _before_ performing IO.  And in interrupt context,
  * check that the pages are still dirty.   If so, fine.  If not, redirty them
  * in process context.
  *
- * We special-case compound pages here: normally this means reads into hugetlb
- * pages.  The logic in here doesn't really work right for compound pages
- * because the VM does not uniformly chase down the head page in all cases.
- * But dirtiness of compound pages is pretty meaningless anyway: the VM doesn't
- * handle them at all.  So we skip compound pages here at an early stage.
- *
  * Note that this code is very hard to test under normal circumstances because
  * direct-io pins the pages with get_user_pages().  This makes
  * is_page_cache_freeable return false, and the VM will not clean the pages.
@@ -1466,12 +1472,12 @@ EXPORT_SYMBOL(bio_free_pages);
  */
 void bio_set_pages_dirty(struct bio *bio)
 {
-       struct bio_vec *bvec;
-       struct bvec_iter_all iter_all;
+       struct folio_iter fi;
 
-       bio_for_each_segment_all(bvec, bio, iter_all) {
-               if (!PageCompound(bvec->bv_page))
-                       set_page_dirty_lock(bvec->bv_page);
+       bio_for_each_folio_all(fi, bio) {
+               folio_lock(fi.folio);
+               folio_mark_dirty(fi.folio);
+               folio_unlock(fi.folio);
        }
 }
 EXPORT_SYMBOL_GPL(bio_set_pages_dirty);
@@ -1515,12 +1521,11 @@ static void bio_dirty_fn(struct work_struct *work)
 
 void bio_check_pages_dirty(struct bio *bio)
 {
-       struct bio_vec *bvec;
+       struct folio_iter fi;
        unsigned long flags;
-       struct bvec_iter_all iter_all;
 
-       bio_for_each_segment_all(bvec, bio, iter_all) {
-               if (!PageDirty(bvec->bv_page) && !PageCompound(bvec->bv_page))
+       bio_for_each_folio_all(fi, bio) {
+               if (!folio_test_dirty(fi.folio))
                        goto defer;
        }