Merge branch 'drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[pandora-kernel.git] / drivers / md / dm.c
index 0d47101..ac384b2 100644 (file)
@@ -1030,17 +1030,27 @@ static void end_clone_request(struct request *clone, int error)
        dm_complete_request(clone, error);
 }
 
-static sector_t max_io_len(struct mapped_device *md,
-                          sector_t sector, struct dm_target *ti)
+/*
+ * Return maximum size of I/O possible at the supplied sector up to the current
+ * target boundary.
+ */
+static sector_t max_io_len_target_boundary(sector_t sector, struct dm_target *ti)
+{
+       sector_t target_offset = dm_target_offset(ti, sector);
+
+       return ti->len - target_offset;
+}
+
+static sector_t max_io_len(sector_t sector, struct dm_target *ti)
 {
-       sector_t offset = sector - ti->begin;
-       sector_t len = ti->len - offset;
+       sector_t len = max_io_len_target_boundary(sector, ti);
 
        /*
         * Does the target need to split even further ?
         */
        if (ti->split_io) {
                sector_t boundary;
+               sector_t offset = dm_target_offset(ti, sector);
                boundary = ((offset + ti->split_io) & ~(ti->split_io - 1))
                           - offset;
                if (len > boundary)
@@ -1182,32 +1192,92 @@ static struct dm_target_io *alloc_tio(struct clone_info *ci,
        return tio;
 }
 
-static void __flush_target(struct clone_info *ci, struct dm_target *ti,
-                         unsigned request_nr)
+static void __issue_target_request(struct clone_info *ci, struct dm_target *ti,
+                                  unsigned request_nr, sector_t len)
 {
        struct dm_target_io *tio = alloc_tio(ci, ti);
        struct bio *clone;
 
        tio->info.target_request_nr = request_nr;
 
-       clone = bio_alloc_bioset(GFP_NOIO, 0, ci->md->bs);
+       /*
+        * Discard requests require the bio's inline iovecs be initialized.
+        * ci->bio->bi_max_vecs is BIO_INLINE_VECS anyway, for both flush
+        * and discard, so no need for concern about wasted bvec allocations.
+        */
+       clone = bio_alloc_bioset(GFP_NOIO, ci->bio->bi_max_vecs, ci->md->bs);
        __bio_clone(clone, ci->bio);
        clone->bi_destructor = dm_bio_destructor;
+       if (len) {
+               clone->bi_sector = ci->sector;
+               clone->bi_size = to_bytes(len);
+       }
 
        __map_bio(ti, clone, tio);
 }
 
+static void __issue_target_requests(struct clone_info *ci, struct dm_target *ti,
+                                   unsigned num_requests, sector_t len)
+{
+       unsigned request_nr;
+
+       for (request_nr = 0; request_nr < num_requests; request_nr++)
+               __issue_target_request(ci, ti, request_nr, len);
+}
+
 static int __clone_and_map_empty_barrier(struct clone_info *ci)
 {
-       unsigned target_nr = 0, request_nr;
+       unsigned target_nr = 0;
        struct dm_target *ti;
 
        while ((ti = dm_table_get_target(ci->map, target_nr++)))
-               for (request_nr = 0; request_nr < ti->num_flush_requests;
-                    request_nr++)
-                       __flush_target(ci, ti, request_nr);
+               __issue_target_requests(ci, ti, ti->num_flush_requests, 0);
+
+       ci->sector_count = 0;
+
+       return 0;
+}
+
+/*
+ * Perform all io with a single clone.
+ */
+static void __clone_and_map_simple(struct clone_info *ci, struct dm_target *ti)
+{
+       struct bio *clone, *bio = ci->bio;
+       struct dm_target_io *tio;
 
+       tio = alloc_tio(ci, ti);
+       clone = clone_bio(bio, ci->sector, ci->idx,
+                         bio->bi_vcnt - ci->idx, ci->sector_count,
+                         ci->md->bs);
+       __map_bio(ti, clone, tio);
        ci->sector_count = 0;
+}
+
+static int __clone_and_map_discard(struct clone_info *ci)
+{
+       struct dm_target *ti;
+       sector_t len;
+
+       do {
+               ti = dm_table_find_target(ci->map, ci->sector);
+               if (!dm_target_is_valid(ti))
+                       return -EIO;
+
+               /*
+                * Even though the device advertised discard support,
+                * reconfiguration might have changed that since the
+                * check was performed.
+                */
+               if (!ti->num_discard_requests)
+                       return -EOPNOTSUPP;
+
+               len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti));
+
+               __issue_target_requests(ci, ti, ti->num_discard_requests, len);
+
+               ci->sector += len;
+       } while (ci->sector_count -= len);
 
        return 0;
 }
@@ -1222,27 +1292,21 @@ static int __clone_and_map(struct clone_info *ci)
        if (unlikely(bio_empty_barrier(bio)))
                return __clone_and_map_empty_barrier(ci);
 
+       if (unlikely(bio->bi_rw & REQ_DISCARD))
+               return __clone_and_map_discard(ci);
+
        ti = dm_table_find_target(ci->map, ci->sector);
        if (!dm_target_is_valid(ti))
                return -EIO;
 
-       max = max_io_len(ci->md, ci->sector, ti);
-
-       /*
-        * Allocate a target io object.
-        */
-       tio = alloc_tio(ci, ti);
+       max = max_io_len(ci->sector, ti);
 
        if (ci->sector_count <= max) {
                /*
                 * Optimise for the simple case where we can do all of
                 * the remaining io with a single clone.
                 */
-               clone = clone_bio(bio, ci->sector, ci->idx,
-                                 bio->bi_vcnt - ci->idx, ci->sector_count,
-                                 ci->md->bs);
-               __map_bio(ti, clone, tio);
-               ci->sector_count = 0;
+               __clone_and_map_simple(ci, ti);
 
        } else if (to_sector(bio->bi_io_vec[ci->idx].bv_len) <= max) {
                /*
@@ -1263,6 +1327,7 @@ static int __clone_and_map(struct clone_info *ci)
                        len += bv_len;
                }
 
+               tio = alloc_tio(ci, ti);
                clone = clone_bio(bio, ci->sector, ci->idx, i - ci->idx, len,
                                  ci->md->bs);
                __map_bio(ti, clone, tio);
@@ -1285,13 +1350,12 @@ static int __clone_and_map(struct clone_info *ci)
                                if (!dm_target_is_valid(ti))
                                        return -EIO;
 
-                               max = max_io_len(ci->md, ci->sector, ti);
-
-                               tio = alloc_tio(ci, ti);
+                               max = max_io_len(ci->sector, ti);
                        }
 
                        len = min(remaining, max);
 
+                       tio = alloc_tio(ci, ti);
                        clone = split_bvec(bio, ci->sector, ci->idx,
                                           bv->bv_offset + offset, len,
                                           ci->md->bs);
@@ -1373,7 +1437,7 @@ static int dm_merge_bvec(struct request_queue *q,
        /*
         * Find maximum amount of I/O that won't need splitting
         */
-       max_sectors = min(max_io_len(md, bvm->bi_sector, ti),
+       max_sectors = min(max_io_len(bvm->bi_sector, ti),
                          (sector_t) BIO_MAX_SECTORS);
        max_size = (max_sectors << SECTOR_SHIFT) - bvm->bi_size;
        if (max_size < 0)