Merge tag 'sound-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
[deliverable/linux.git] / drivers / md / dm.c
index e24143cc2040b7f3f8f90a63c3b1b2cfe2b21c24..4e09b6ff5b493403d4e51be0b4fee2d99643e276 100644 (file)
@@ -968,22 +968,41 @@ static sector_t max_io_len_target_boundary(sector_t sector, struct dm_target *ti
 static sector_t max_io_len(sector_t sector, struct dm_target *ti)
 {
        sector_t len = max_io_len_target_boundary(sector, ti);
+       sector_t offset, max_len;
 
        /*
-        * Does the target need to split even further ?
+        * 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)
-                       len = boundary;
+       if (ti->max_io_len) {
+               offset = dm_target_offset(ti, sector);
+               if (unlikely(ti->max_io_len & (ti->max_io_len - 1)))
+                       max_len = sector_div(offset, ti->max_io_len);
+               else
+                       max_len = offset & (ti->max_io_len - 1);
+               max_len = ti->max_io_len - max_len;
+
+               if (len > max_len)
+                       len = max_len;
        }
 
        return len;
 }
 
+int dm_set_target_max_io_len(struct dm_target *ti, sector_t len)
+{
+       if (len > UINT_MAX) {
+               DMERR("Specified maximum size of target IO (%llu) exceeds limit (%u)",
+                     (unsigned long long)len, UINT_MAX);
+               ti->error = "Maximum size of target IO is too large";
+               return -EINVAL;
+       }
+
+       ti->max_io_len = (uint32_t) len;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dm_set_target_max_io_len);
+
 static void __map_bio(struct dm_target *ti, struct bio *clone,
                      struct dm_target_io *tio)
 {
@@ -1196,7 +1215,10 @@ static int __clone_and_map_discard(struct clone_info *ci)
                if (!ti->num_discard_requests)
                        return -EOPNOTSUPP;
 
-               len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti));
+               if (!ti->split_discard_requests)
+                       len = min(ci->sector_count, max_io_len_target_boundary(ci->sector, ti));
+               else
+                       len = min(ci->sector_count, max_io_len(ci->sector, ti));
 
                __issue_target_requests(ci, ti, ti->num_discard_requests, len);
 
This page took 0.027476 seconds and 5 git commands to generate.