]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blobdiff - fs/buffer.c
tools build: Use $(shell ) instead of `` to get embedded libperl's ccopts
[mirror_ubuntu-focal-kernel.git] / fs / buffer.c
index 86a38b979323547cb01c3c0f0257ec5dd93efc6d..0d7bd7712076d60d63c22d7f4eb12a62e6a7782e 100644 (file)
@@ -1337,6 +1337,17 @@ void __breadahead(struct block_device *bdev, sector_t block, unsigned size)
 }
 EXPORT_SYMBOL(__breadahead);
 
+void __breadahead_gfp(struct block_device *bdev, sector_t block, unsigned size,
+                     gfp_t gfp)
+{
+       struct buffer_head *bh = __getblk_gfp(bdev, block, size, gfp);
+       if (likely(bh)) {
+               ll_rw_block(REQ_OP_READ, REQ_RAHEAD, 1, &bh);
+               brelse(bh);
+       }
+}
+EXPORT_SYMBOL(__breadahead_gfp);
+
 /**
  *  __bread_gfp() - reads a specified block and returns the bh
  *  @bdev: the block_device to read from
@@ -2728,16 +2739,6 @@ int nobh_writepage(struct page *page, get_block_t *get_block,
        /* Is the page fully outside i_size? (truncate in progress) */
        offset = i_size & (PAGE_SIZE-1);
        if (page->index >= end_index+1 || !offset) {
-               /*
-                * The page may have dirty, unmapped buffers.  For example,
-                * they may have been added in ext3_writepage().  Make them
-                * freeable here, so the page does not leak.
-                */
-#if 0
-               /* Not really sure about this  - do we need this ? */
-               if (page->mapping->a_ops->invalidatepage)
-                       page->mapping->a_ops->invalidatepage(page, offset);
-#endif
                unlock_page(page);
                return 0; /* don't care */
        }
@@ -2932,12 +2933,6 @@ int block_write_full_page(struct page *page, get_block_t *get_block,
        /* Is the page fully outside i_size? (truncate in progress) */
        offset = i_size & (PAGE_SIZE-1);
        if (page->index >= end_index+1 || !offset) {
-               /*
-                * The page may have dirty, unmapped buffers.  For example,
-                * they may have been added in ext3_writepage().  Make them
-                * freeable here, so the page does not leak.
-                */
-               do_invalidatepage(page, 0, PAGE_SIZE);
                unlock_page(page);
                return 0; /* don't care */
        }
@@ -2991,11 +2986,9 @@ static void end_bio_bh_io_sync(struct bio *bio)
  * errors, this only handles the "we need to be able to
  * do IO at the final sector" case.
  */
-void guard_bio_eod(int op, struct bio *bio)
+void guard_bio_eod(struct bio *bio)
 {
        sector_t maxsector;
-       struct bio_vec *bvec = bio_last_bvec_all(bio);
-       unsigned truncated_bytes;
        struct hd_struct *part;
 
        rcu_read_lock();
@@ -3021,28 +3014,7 @@ void guard_bio_eod(int op, struct bio *bio)
        if (likely((bio->bi_iter.bi_size >> 9) <= maxsector))
                return;
 
-       /* Uhhuh. We've got a bio that straddles the device size! */
-       truncated_bytes = bio->bi_iter.bi_size - (maxsector << 9);
-
-       /*
-        * The bio contains more than one segment which spans EOD, just return
-        * and let IO layer turn it into an EIO
-        */
-       if (truncated_bytes > bvec->bv_len)
-               return;
-
-       /* Truncate the bio.. */
-       bio->bi_iter.bi_size -= truncated_bytes;
-       bvec->bv_len -= truncated_bytes;
-
-       /* ..and clear the end of the buffer for reads */
-       if (op == REQ_OP_READ) {
-               struct bio_vec bv;
-
-               mp_bvec_last_segment(bvec, &bv);
-               zero_user(bv.bv_page, bv.bv_offset + bv.bv_len,
-                               truncated_bytes);
-       }
+       bio_truncate(bio, maxsector << 9);
 }
 
 static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh,
@@ -3078,15 +3050,15 @@ static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh,
        bio->bi_end_io = end_bio_bh_io_sync;
        bio->bi_private = bh;
 
-       /* Take care of bh's that straddle the end of the device */
-       guard_bio_eod(op, bio);
-
        if (buffer_meta(bh))
                op_flags |= REQ_META;
        if (buffer_prio(bh))
                op_flags |= REQ_PRIO;
        bio_set_op_attrs(bio, op, op_flags);
 
+       /* Take care of bh's that straddle the end of the device */
+       guard_bio_eod(bio);
+
        if (wbc) {
                wbc_init_bio(wbc, bio);
                wbc_account_cgroup_owner(wbc, bh->b_page, bh->b_size);
@@ -3182,6 +3154,15 @@ int __sync_dirty_buffer(struct buffer_head *bh, int op_flags)
        WARN_ON(atomic_read(&bh->b_count) < 1);
        lock_buffer(bh);
        if (test_clear_buffer_dirty(bh)) {
+               /*
+                * The bh should be mapped, but it might not be if the
+                * device was hot-removed. Not much we can do but fail the I/O.
+                */
+               if (!buffer_mapped(bh)) {
+                       unlock_buffer(bh);
+                       return -EIO;
+               }
+
                get_bh(bh);
                bh->b_end_io = end_buffer_write_sync;
                ret = submit_bh(REQ_OP_WRITE, op_flags, bh);