]> git.ipfire.org Git - people/arne_f/kernel.git/blobdiff - fs/buffer.c
iio:magnetometer:ak8975 Fix alignment and data leak issues.
[people/arne_f/kernel.git] / fs / buffer.c
index 170df856bdb99715b126b2d129ff19ea95d46ad8..9fbeddb6834a4c46905f9d4fd109020140138909 100644 (file)
@@ -208,6 +208,7 @@ __find_get_block_slow(struct block_device *bdev, sector_t block)
        struct buffer_head *head;
        struct page *page;
        int all_mapped = 1;
+       static DEFINE_RATELIMIT_STATE(last_warned, HZ, 1);
 
        index = block >> (PAGE_SHIFT - bd_inode->i_blkbits);
        page = find_get_page_flags(bd_mapping, index, FGP_ACCESSED);
@@ -235,15 +236,15 @@ __find_get_block_slow(struct block_device *bdev, sector_t block)
         * file io on the block device and getblk.  It gets dealt with
         * elsewhere, don't buffer_error if we had some unmapped buffers
         */
-       if (all_mapped) {
-               printk("__find_get_block_slow() failed. "
-                       "block=%llu, b_blocknr=%llu\n",
-                       (unsigned long long)block,
-                       (unsigned long long)bh->b_blocknr);
-               printk("b_state=0x%08lx, b_size=%zu\n",
-                       bh->b_state, bh->b_size);
-               printk("device %pg blocksize: %d\n", bdev,
-                       1 << bd_inode->i_blkbits);
+       ratelimit_set_flags(&last_warned, RATELIMIT_MSG_ON_RELEASE);
+       if (all_mapped && __ratelimit(&last_warned)) {
+               printk("__find_get_block_slow() failed. block=%llu, "
+                      "b_blocknr=%llu, b_state=0x%08lx, b_size=%zu, "
+                      "device %pg blocksize: %d\n",
+                      (unsigned long long)block,
+                      (unsigned long long)bh->b_blocknr,
+                      bh->b_state, bh->b_size, bdev,
+                      1 << bd_inode->i_blkbits);
        }
 out_unlock:
        spin_unlock(&bd_mapping->private_lock);
@@ -1397,6 +1398,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
@@ -3055,8 +3067,16 @@ void guard_bio_eod(int op, struct bio *bio)
        sector_t maxsector;
        struct bio_vec *bvec = &bio->bi_io_vec[bio->bi_vcnt - 1];
        unsigned truncated_bytes;
+       struct hd_struct *part;
+
+       rcu_read_lock();
+       part = __disk_get_part(bio->bi_disk, bio->bi_partno);
+       if (part)
+               maxsector = part_nr_sects_read(part);
+       else
+               maxsector = get_capacity(bio->bi_disk);
+       rcu_read_unlock();
 
-       maxsector = get_capacity(bio->bi_disk);
        if (!maxsector)
                return;
 
@@ -3075,6 +3095,13 @@ void guard_bio_eod(int op, struct bio *bio)
        /* 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;
@@ -3223,6 +3250,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);