Merge branch 'pm-cpuidle'
[linux-drm-fsl-dcu.git] / fs / bio.c
index ea5035da4d9a0cd9fd6f5f657bb01272c63175c3..2bdb4e25ee77db6c2a5c135b3c726eae734153b9 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -1804,6 +1804,52 @@ struct bio_pair *bio_split(struct bio *bi, int first_sectors)
 }
 EXPORT_SYMBOL(bio_split);
 
+/**
+ * bio_trim - trim a bio
+ * @bio:       bio to trim
+ * @offset:    number of sectors to trim from the front of @bio
+ * @size:      size we want to trim @bio to, in sectors
+ */
+void bio_trim(struct bio *bio, int offset, int size)
+{
+       /* 'bio' is a cloned bio which we need to trim to match
+        * the given offset and size.
+        * This requires adjusting bi_sector, bi_size, and bi_io_vec
+        */
+       int i;
+       struct bio_vec *bvec;
+       int sofar = 0;
+
+       size <<= 9;
+       if (offset == 0 && size == bio->bi_size)
+               return;
+
+       clear_bit(BIO_SEG_VALID, &bio->bi_flags);
+
+       bio_advance(bio, offset << 9);
+
+       bio->bi_size = size;
+
+       /* avoid any complications with bi_idx being non-zero*/
+       if (bio->bi_idx) {
+               memmove(bio->bi_io_vec, bio->bi_io_vec+bio->bi_idx,
+                       (bio->bi_vcnt - bio->bi_idx) * sizeof(struct bio_vec));
+               bio->bi_vcnt -= bio->bi_idx;
+               bio->bi_idx = 0;
+       }
+       /* Make sure vcnt and last bv are not too big */
+       bio_for_each_segment(bvec, bio, i) {
+               if (sofar + bvec->bv_len > size)
+                       bvec->bv_len = size - sofar;
+               if (bvec->bv_len == 0) {
+                       bio->bi_vcnt = i;
+                       break;
+               }
+               sofar += bvec->bv_len;
+       }
+}
+EXPORT_SYMBOL_GPL(bio_trim);
+
 /**
  *      bio_sector_offset - Find hardware sector offset in bio
  *      @bio:           bio to inspect