OSDN Git Service

Merge android-4.4-p.198 (dbd0162) into msm-4.4
[sagit-ice-cold/kernel_xiaomi_msm8998.git] / drivers / block / loop.c
index 8aadd4d..aa7895f 100644 (file)
@@ -1070,6 +1070,7 @@ static int loop_clr_fd(struct loop_device *lo)
        memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
        memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
        memset(lo->lo_file_name, 0, LO_NAME_SIZE);
+       blk_queue_logical_block_size(lo->lo_queue, 512);
        if (bdev) {
                bdput(bdev);
                invalidate_bdev(bdev);
@@ -1120,6 +1121,12 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
        if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE)
                return -EINVAL;
 
+       if (lo->lo_offset != info->lo_offset ||
+           lo->lo_sizelimit != info->lo_sizelimit) {
+               sync_blockdev(lo->lo_device);
+               kill_bdev(lo->lo_device);
+       }
+
        /* I/O need to be drained during transfer transition */
        blk_mq_freeze_queue(lo->lo_queue);
 
@@ -1147,11 +1154,20 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
                goto exit;
 
        if (lo->lo_offset != info->lo_offset ||
-           lo->lo_sizelimit != info->lo_sizelimit)
+           lo->lo_sizelimit != info->lo_sizelimit) {
+               /* kill_bdev should have truncated all the pages */
+               if (lo->lo_device->bd_inode->i_mapping->nrpages) {
+                       err = -EAGAIN;
+                       pr_warn("%s: loop%d (%s) has still dirty pages (nrpages=%lu)\n",
+                               __func__, lo->lo_number, lo->lo_file_name,
+                               lo->lo_device->bd_inode->i_mapping->nrpages);
+                       goto exit;
+               }
                if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit)) {
                        err = -EFBIG;
                        goto exit;
                }
+       }
 
        loop_config_discard(lo);
 
@@ -1355,6 +1371,41 @@ static int loop_set_dio(struct loop_device *lo, unsigned long arg)
        return error;
 }
 
+static int loop_set_block_size(struct loop_device *lo, unsigned long arg)
+{
+       int err = 0;
+
+       if (lo->lo_state != Lo_bound)
+               return -ENXIO;
+
+       if (arg < 512 || arg > PAGE_SIZE || !is_power_of_2(arg))
+               return -EINVAL;
+
+       if (lo->lo_queue->limits.logical_block_size != arg) {
+               sync_blockdev(lo->lo_device);
+               kill_bdev(lo->lo_device);
+       }
+
+       blk_mq_freeze_queue(lo->lo_queue);
+
+       /* kill_bdev should have truncated all the pages */
+       if (lo->lo_queue->limits.logical_block_size != arg &&
+                       lo->lo_device->bd_inode->i_mapping->nrpages) {
+               err = -EAGAIN;
+               pr_warn("%s: loop%d (%s) has still dirty pages (nrpages=%lu)\n",
+                       __func__, lo->lo_number, lo->lo_file_name,
+                       lo->lo_device->bd_inode->i_mapping->nrpages);
+               goto out_unfreeze;
+       }
+
+       blk_queue_logical_block_size(lo->lo_queue, arg);
+       loop_update_dio(lo);
+out_unfreeze:
+       blk_mq_unfreeze_queue(lo->lo_queue);
+
+       return err;
+}
+
 static int lo_ioctl(struct block_device *bdev, fmode_t mode,
        unsigned int cmd, unsigned long arg)
 {
@@ -1403,6 +1454,11 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
                if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
                        err = loop_set_dio(lo, arg);
                break;
+       case LOOP_SET_BLOCK_SIZE:
+               err = -EPERM;
+               if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
+                       err = loop_set_block_size(lo, arg);
+               break;
        default:
                err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
        }
@@ -1557,6 +1613,7 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode,
                arg = (unsigned long) compat_ptr(arg);
        case LOOP_SET_FD:
        case LOOP_CHANGE_FD:
+       case LOOP_SET_BLOCK_SIZE:
        case LOOP_SET_DIRECT_IO:
                err = lo_ioctl(bdev, mode, cmd, arg);
                break;
@@ -1790,6 +1847,7 @@ static int loop_add(struct loop_device **l, int i)
        }
        lo->lo_queue->queuedata = lo;
 
+       blk_queue_max_hw_sectors(lo->lo_queue, BLK_DEF_MAX_SECTORS);
        /*
         * It doesn't make sense to enable merge because the I/O
         * submitted to backing file is handled page by page.