18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/drivers/block/loop.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Written by Theodore Ts'o, 3/29/93 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright 1993 by Theodore Ts'o. Redistribution of this file is 78c2ecf20Sopenharmony_ci * permitted under the GNU General Public License. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * DES encryption plus some minor changes by Werner Almesberger, 30-MAY-1993 108c2ecf20Sopenharmony_ci * more DES encryption plus IDEA encryption by Nicholas J. Leon, June 20, 1996 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Modularized and updated for 1.1.16 kernel - Mitch Dsouza 28th May 1994 138c2ecf20Sopenharmony_ci * Adapted for 1.3.59 kernel - Andries Brouwer, 1 Feb 1996 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Fixed do_loop_request() re-entrancy - Vincent.Renardias@waw.com Mar 20, 1997 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Added devfs support - Richard Gooch <rgooch@atnf.csiro.au> 16-Jan-1998 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * Handle sparse backing files correctly - Kenn Humborg, Jun 28, 1998 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * Loadable modules and other fixes by AK, 1998 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * Make real block number available to downstream transfer functions, enables 248c2ecf20Sopenharmony_ci * CBC (and relatives) mode encryption requiring unique IVs per data block. 258c2ecf20Sopenharmony_ci * Reed H. Petty, rhp@draper.net 268c2ecf20Sopenharmony_ci * 278c2ecf20Sopenharmony_ci * Maximum number of loop devices now dynamic via max_loop module parameter. 288c2ecf20Sopenharmony_ci * Russell Kroll <rkroll@exploits.org> 19990701 298c2ecf20Sopenharmony_ci * 308c2ecf20Sopenharmony_ci * Maximum number of loop devices when compiled-in now selectable by passing 318c2ecf20Sopenharmony_ci * max_loop=<1-255> to the kernel on boot. 328c2ecf20Sopenharmony_ci * Erik I. Bolsø, <eriki@himolde.no>, Oct 31, 1999 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * Completely rewrite request handling to be make_request_fn style and 358c2ecf20Sopenharmony_ci * non blocking, pushing work to a helper thread. Lots of fixes from 368c2ecf20Sopenharmony_ci * Al Viro too. 378c2ecf20Sopenharmony_ci * Jens Axboe <axboe@suse.de>, Nov 2000 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * Support up to 256 loop devices 408c2ecf20Sopenharmony_ci * Heinz Mauelshagen <mge@sistina.com>, Feb 2002 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * Support for falling back on the write file operation when the address space 438c2ecf20Sopenharmony_ci * operations write_begin is not available on the backing filesystem. 448c2ecf20Sopenharmony_ci * Anton Altaparmakov, 16 Feb 2005 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * Still To Fix: 478c2ecf20Sopenharmony_ci * - Advisory locking is ignored here. 488c2ecf20Sopenharmony_ci * - Should use an own CAP_* category instead of CAP_SYS_ADMIN 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci#include <linux/module.h> 538c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 548c2ecf20Sopenharmony_ci#include <linux/sched.h> 558c2ecf20Sopenharmony_ci#include <linux/fs.h> 568c2ecf20Sopenharmony_ci#include <linux/file.h> 578c2ecf20Sopenharmony_ci#include <linux/stat.h> 588c2ecf20Sopenharmony_ci#include <linux/errno.h> 598c2ecf20Sopenharmony_ci#include <linux/major.h> 608c2ecf20Sopenharmony_ci#include <linux/wait.h> 618c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 628c2ecf20Sopenharmony_ci#include <linux/blkpg.h> 638c2ecf20Sopenharmony_ci#include <linux/init.h> 648c2ecf20Sopenharmony_ci#include <linux/swap.h> 658c2ecf20Sopenharmony_ci#include <linux/slab.h> 668c2ecf20Sopenharmony_ci#include <linux/compat.h> 678c2ecf20Sopenharmony_ci#include <linux/suspend.h> 688c2ecf20Sopenharmony_ci#include <linux/freezer.h> 698c2ecf20Sopenharmony_ci#include <linux/mutex.h> 708c2ecf20Sopenharmony_ci#include <linux/writeback.h> 718c2ecf20Sopenharmony_ci#include <linux/completion.h> 728c2ecf20Sopenharmony_ci#include <linux/highmem.h> 738c2ecf20Sopenharmony_ci#include <linux/kthread.h> 748c2ecf20Sopenharmony_ci#include <linux/splice.h> 758c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 768c2ecf20Sopenharmony_ci#include <linux/miscdevice.h> 778c2ecf20Sopenharmony_ci#include <linux/falloc.h> 788c2ecf20Sopenharmony_ci#include <linux/uio.h> 798c2ecf20Sopenharmony_ci#include <linux/ioprio.h> 808c2ecf20Sopenharmony_ci#include <linux/blk-cgroup.h> 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci#include "loop.h" 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic DEFINE_IDR(loop_index_idr); 878c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(loop_ctl_mutex); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic int max_part; 908c2ecf20Sopenharmony_cistatic int part_shift; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic int transfer_xor(struct loop_device *lo, int cmd, 938c2ecf20Sopenharmony_ci struct page *raw_page, unsigned raw_off, 948c2ecf20Sopenharmony_ci struct page *loop_page, unsigned loop_off, 958c2ecf20Sopenharmony_ci int size, sector_t real_block) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci char *raw_buf = kmap_atomic(raw_page) + raw_off; 988c2ecf20Sopenharmony_ci char *loop_buf = kmap_atomic(loop_page) + loop_off; 998c2ecf20Sopenharmony_ci char *in, *out, *key; 1008c2ecf20Sopenharmony_ci int i, keysize; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci if (cmd == READ) { 1038c2ecf20Sopenharmony_ci in = raw_buf; 1048c2ecf20Sopenharmony_ci out = loop_buf; 1058c2ecf20Sopenharmony_ci } else { 1068c2ecf20Sopenharmony_ci in = loop_buf; 1078c2ecf20Sopenharmony_ci out = raw_buf; 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci key = lo->lo_encrypt_key; 1118c2ecf20Sopenharmony_ci keysize = lo->lo_encrypt_key_size; 1128c2ecf20Sopenharmony_ci for (i = 0; i < size; i++) 1138c2ecf20Sopenharmony_ci *out++ = *in++ ^ key[(i & 511) % keysize]; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci kunmap_atomic(loop_buf); 1168c2ecf20Sopenharmony_ci kunmap_atomic(raw_buf); 1178c2ecf20Sopenharmony_ci cond_resched(); 1188c2ecf20Sopenharmony_ci return 0; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int xor_init(struct loop_device *lo, const struct loop_info64 *info) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci if (unlikely(info->lo_encrypt_key_size <= 0)) 1248c2ecf20Sopenharmony_ci return -EINVAL; 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic struct loop_func_table none_funcs = { 1298c2ecf20Sopenharmony_ci .number = LO_CRYPT_NONE, 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic struct loop_func_table xor_funcs = { 1338c2ecf20Sopenharmony_ci .number = LO_CRYPT_XOR, 1348c2ecf20Sopenharmony_ci .transfer = transfer_xor, 1358c2ecf20Sopenharmony_ci .init = xor_init 1368c2ecf20Sopenharmony_ci}; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* xfer_funcs[0] is special - its release function is never called */ 1398c2ecf20Sopenharmony_cistatic struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = { 1408c2ecf20Sopenharmony_ci &none_funcs, 1418c2ecf20Sopenharmony_ci &xor_funcs 1428c2ecf20Sopenharmony_ci}; 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic loff_t get_size(loff_t offset, loff_t sizelimit, struct file *file) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci loff_t loopsize; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* Compute loopsize in bytes */ 1498c2ecf20Sopenharmony_ci loopsize = i_size_read(file->f_mapping->host); 1508c2ecf20Sopenharmony_ci if (offset > 0) 1518c2ecf20Sopenharmony_ci loopsize -= offset; 1528c2ecf20Sopenharmony_ci /* offset is beyond i_size, weird but possible */ 1538c2ecf20Sopenharmony_ci if (loopsize < 0) 1548c2ecf20Sopenharmony_ci return 0; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (sizelimit > 0 && sizelimit < loopsize) 1578c2ecf20Sopenharmony_ci loopsize = sizelimit; 1588c2ecf20Sopenharmony_ci /* 1598c2ecf20Sopenharmony_ci * Unfortunately, if we want to do I/O on the device, 1608c2ecf20Sopenharmony_ci * the number of 512-byte sectors has to fit into a sector_t. 1618c2ecf20Sopenharmony_ci */ 1628c2ecf20Sopenharmony_ci return loopsize >> 9; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic loff_t get_loop_size(struct loop_device *lo, struct file *file) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci return get_size(lo->lo_offset, lo->lo_sizelimit, file); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic void __loop_update_dio(struct loop_device *lo, bool dio) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct file *file = lo->lo_backing_file; 1738c2ecf20Sopenharmony_ci struct address_space *mapping = file->f_mapping; 1748c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 1758c2ecf20Sopenharmony_ci unsigned short sb_bsize = 0; 1768c2ecf20Sopenharmony_ci unsigned dio_align = 0; 1778c2ecf20Sopenharmony_ci bool use_dio; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (inode->i_sb->s_bdev) { 1808c2ecf20Sopenharmony_ci sb_bsize = bdev_logical_block_size(inode->i_sb->s_bdev); 1818c2ecf20Sopenharmony_ci dio_align = sb_bsize - 1; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* 1858c2ecf20Sopenharmony_ci * We support direct I/O only if lo_offset is aligned with the 1868c2ecf20Sopenharmony_ci * logical I/O size of backing device, and the logical block 1878c2ecf20Sopenharmony_ci * size of loop is bigger than the backing device's and the loop 1888c2ecf20Sopenharmony_ci * needn't transform transfer. 1898c2ecf20Sopenharmony_ci * 1908c2ecf20Sopenharmony_ci * TODO: the above condition may be loosed in the future, and 1918c2ecf20Sopenharmony_ci * direct I/O may be switched runtime at that time because most 1928c2ecf20Sopenharmony_ci * of requests in sane applications should be PAGE_SIZE aligned 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_ci if (dio) { 1958c2ecf20Sopenharmony_ci if (queue_logical_block_size(lo->lo_queue) >= sb_bsize && 1968c2ecf20Sopenharmony_ci !(lo->lo_offset & dio_align) && 1978c2ecf20Sopenharmony_ci mapping->a_ops->direct_IO && 1988c2ecf20Sopenharmony_ci !lo->transfer) 1998c2ecf20Sopenharmony_ci use_dio = true; 2008c2ecf20Sopenharmony_ci else 2018c2ecf20Sopenharmony_ci use_dio = false; 2028c2ecf20Sopenharmony_ci } else { 2038c2ecf20Sopenharmony_ci use_dio = false; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (lo->use_dio == use_dio) 2078c2ecf20Sopenharmony_ci return; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* flush dirty pages before changing direct IO */ 2108c2ecf20Sopenharmony_ci vfs_fsync(file, 0); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci /* 2138c2ecf20Sopenharmony_ci * The flag of LO_FLAGS_DIRECT_IO is handled similarly with 2148c2ecf20Sopenharmony_ci * LO_FLAGS_READ_ONLY, both are set from kernel, and losetup 2158c2ecf20Sopenharmony_ci * will get updated by ioctl(LOOP_GET_STATUS) 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_ci if (lo->lo_state == Lo_bound) 2188c2ecf20Sopenharmony_ci blk_mq_freeze_queue(lo->lo_queue); 2198c2ecf20Sopenharmony_ci lo->use_dio = use_dio; 2208c2ecf20Sopenharmony_ci if (use_dio) { 2218c2ecf20Sopenharmony_ci blk_queue_flag_clear(QUEUE_FLAG_NOMERGES, lo->lo_queue); 2228c2ecf20Sopenharmony_ci lo->lo_flags |= LO_FLAGS_DIRECT_IO; 2238c2ecf20Sopenharmony_ci } else { 2248c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_NOMERGES, lo->lo_queue); 2258c2ecf20Sopenharmony_ci lo->lo_flags &= ~LO_FLAGS_DIRECT_IO; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci if (lo->lo_state == Lo_bound) 2288c2ecf20Sopenharmony_ci blk_mq_unfreeze_queue(lo->lo_queue); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci/** 2328c2ecf20Sopenharmony_ci * loop_set_size() - sets device size and notifies userspace 2338c2ecf20Sopenharmony_ci * @lo: struct loop_device to set the size for 2348c2ecf20Sopenharmony_ci * @size: new size of the loop device 2358c2ecf20Sopenharmony_ci * 2368c2ecf20Sopenharmony_ci * Callers must validate that the size passed into this function fits into 2378c2ecf20Sopenharmony_ci * a sector_t, eg using loop_validate_size() 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_cistatic void loop_set_size(struct loop_device *lo, loff_t size) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct block_device *bdev = lo->lo_device; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci bd_set_nr_sectors(bdev, size); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci if (!set_capacity_revalidate_and_notify(lo->lo_disk, size, false)) 2468c2ecf20Sopenharmony_ci kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic inline int 2508c2ecf20Sopenharmony_cilo_do_transfer(struct loop_device *lo, int cmd, 2518c2ecf20Sopenharmony_ci struct page *rpage, unsigned roffs, 2528c2ecf20Sopenharmony_ci struct page *lpage, unsigned loffs, 2538c2ecf20Sopenharmony_ci int size, sector_t rblock) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci int ret; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci ret = lo->transfer(lo, cmd, rpage, roffs, lpage, loffs, size, rblock); 2588c2ecf20Sopenharmony_ci if (likely(!ret)) 2598c2ecf20Sopenharmony_ci return 0; 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci printk_ratelimited(KERN_ERR 2628c2ecf20Sopenharmony_ci "loop: Transfer error at byte offset %llu, length %i.\n", 2638c2ecf20Sopenharmony_ci (unsigned long long)rblock << 9, size); 2648c2ecf20Sopenharmony_ci return ret; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic int lo_write_bvec(struct file *file, struct bio_vec *bvec, loff_t *ppos) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct iov_iter i; 2708c2ecf20Sopenharmony_ci ssize_t bw; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci iov_iter_bvec(&i, WRITE, bvec, 1, bvec->bv_len); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci file_start_write(file); 2758c2ecf20Sopenharmony_ci bw = vfs_iter_write(file, &i, ppos, 0); 2768c2ecf20Sopenharmony_ci file_end_write(file); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (likely(bw == bvec->bv_len)) 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci printk_ratelimited(KERN_ERR 2828c2ecf20Sopenharmony_ci "loop: Write error at byte offset %llu, length %i.\n", 2838c2ecf20Sopenharmony_ci (unsigned long long)*ppos, bvec->bv_len); 2848c2ecf20Sopenharmony_ci if (bw >= 0) 2858c2ecf20Sopenharmony_ci bw = -EIO; 2868c2ecf20Sopenharmony_ci return bw; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic int lo_write_simple(struct loop_device *lo, struct request *rq, 2908c2ecf20Sopenharmony_ci loff_t pos) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct bio_vec bvec; 2938c2ecf20Sopenharmony_ci struct req_iterator iter; 2948c2ecf20Sopenharmony_ci int ret = 0; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci rq_for_each_segment(bvec, rq, iter) { 2978c2ecf20Sopenharmony_ci ret = lo_write_bvec(lo->lo_backing_file, &bvec, &pos); 2988c2ecf20Sopenharmony_ci if (ret < 0) 2998c2ecf20Sopenharmony_ci break; 3008c2ecf20Sopenharmony_ci cond_resched(); 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return ret; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci/* 3078c2ecf20Sopenharmony_ci * This is the slow, transforming version that needs to double buffer the 3088c2ecf20Sopenharmony_ci * data as it cannot do the transformations in place without having direct 3098c2ecf20Sopenharmony_ci * access to the destination pages of the backing file. 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_cistatic int lo_write_transfer(struct loop_device *lo, struct request *rq, 3128c2ecf20Sopenharmony_ci loff_t pos) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct bio_vec bvec, b; 3158c2ecf20Sopenharmony_ci struct req_iterator iter; 3168c2ecf20Sopenharmony_ci struct page *page; 3178c2ecf20Sopenharmony_ci int ret = 0; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci page = alloc_page(GFP_NOIO); 3208c2ecf20Sopenharmony_ci if (unlikely(!page)) 3218c2ecf20Sopenharmony_ci return -ENOMEM; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci rq_for_each_segment(bvec, rq, iter) { 3248c2ecf20Sopenharmony_ci ret = lo_do_transfer(lo, WRITE, page, 0, bvec.bv_page, 3258c2ecf20Sopenharmony_ci bvec.bv_offset, bvec.bv_len, pos >> 9); 3268c2ecf20Sopenharmony_ci if (unlikely(ret)) 3278c2ecf20Sopenharmony_ci break; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci b.bv_page = page; 3308c2ecf20Sopenharmony_ci b.bv_offset = 0; 3318c2ecf20Sopenharmony_ci b.bv_len = bvec.bv_len; 3328c2ecf20Sopenharmony_ci ret = lo_write_bvec(lo->lo_backing_file, &b, &pos); 3338c2ecf20Sopenharmony_ci if (ret < 0) 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci __free_page(page); 3388c2ecf20Sopenharmony_ci return ret; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic int lo_read_simple(struct loop_device *lo, struct request *rq, 3428c2ecf20Sopenharmony_ci loff_t pos) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci struct bio_vec bvec; 3458c2ecf20Sopenharmony_ci struct req_iterator iter; 3468c2ecf20Sopenharmony_ci struct iov_iter i; 3478c2ecf20Sopenharmony_ci ssize_t len; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci rq_for_each_segment(bvec, rq, iter) { 3508c2ecf20Sopenharmony_ci iov_iter_bvec(&i, READ, &bvec, 1, bvec.bv_len); 3518c2ecf20Sopenharmony_ci len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0); 3528c2ecf20Sopenharmony_ci if (len < 0) 3538c2ecf20Sopenharmony_ci return len; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci flush_dcache_page(bvec.bv_page); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (len != bvec.bv_len) { 3588c2ecf20Sopenharmony_ci struct bio *bio; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci __rq_for_each_bio(bio, rq) 3618c2ecf20Sopenharmony_ci zero_fill_bio(bio); 3628c2ecf20Sopenharmony_ci break; 3638c2ecf20Sopenharmony_ci } 3648c2ecf20Sopenharmony_ci cond_resched(); 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int lo_read_transfer(struct loop_device *lo, struct request *rq, 3718c2ecf20Sopenharmony_ci loff_t pos) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct bio_vec bvec, b; 3748c2ecf20Sopenharmony_ci struct req_iterator iter; 3758c2ecf20Sopenharmony_ci struct iov_iter i; 3768c2ecf20Sopenharmony_ci struct page *page; 3778c2ecf20Sopenharmony_ci ssize_t len; 3788c2ecf20Sopenharmony_ci int ret = 0; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci page = alloc_page(GFP_NOIO); 3818c2ecf20Sopenharmony_ci if (unlikely(!page)) 3828c2ecf20Sopenharmony_ci return -ENOMEM; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci rq_for_each_segment(bvec, rq, iter) { 3858c2ecf20Sopenharmony_ci loff_t offset = pos; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci b.bv_page = page; 3888c2ecf20Sopenharmony_ci b.bv_offset = 0; 3898c2ecf20Sopenharmony_ci b.bv_len = bvec.bv_len; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci iov_iter_bvec(&i, READ, &b, 1, b.bv_len); 3928c2ecf20Sopenharmony_ci len = vfs_iter_read(lo->lo_backing_file, &i, &pos, 0); 3938c2ecf20Sopenharmony_ci if (len < 0) { 3948c2ecf20Sopenharmony_ci ret = len; 3958c2ecf20Sopenharmony_ci goto out_free_page; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci ret = lo_do_transfer(lo, READ, page, 0, bvec.bv_page, 3998c2ecf20Sopenharmony_ci bvec.bv_offset, len, offset >> 9); 4008c2ecf20Sopenharmony_ci if (ret) 4018c2ecf20Sopenharmony_ci goto out_free_page; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci flush_dcache_page(bvec.bv_page); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci if (len != bvec.bv_len) { 4068c2ecf20Sopenharmony_ci struct bio *bio; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci __rq_for_each_bio(bio, rq) 4098c2ecf20Sopenharmony_ci zero_fill_bio(bio); 4108c2ecf20Sopenharmony_ci break; 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci ret = 0; 4158c2ecf20Sopenharmony_ciout_free_page: 4168c2ecf20Sopenharmony_ci __free_page(page); 4178c2ecf20Sopenharmony_ci return ret; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_cistatic int lo_fallocate(struct loop_device *lo, struct request *rq, loff_t pos, 4218c2ecf20Sopenharmony_ci int mode) 4228c2ecf20Sopenharmony_ci{ 4238c2ecf20Sopenharmony_ci /* 4248c2ecf20Sopenharmony_ci * We use fallocate to manipulate the space mappings used by the image 4258c2ecf20Sopenharmony_ci * a.k.a. discard/zerorange. However we do not support this if 4268c2ecf20Sopenharmony_ci * encryption is enabled, because it may give an attacker useful 4278c2ecf20Sopenharmony_ci * information. 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_ci struct file *file = lo->lo_backing_file; 4308c2ecf20Sopenharmony_ci struct request_queue *q = lo->lo_queue; 4318c2ecf20Sopenharmony_ci int ret; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci mode |= FALLOC_FL_KEEP_SIZE; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (!blk_queue_discard(q)) { 4368c2ecf20Sopenharmony_ci ret = -EOPNOTSUPP; 4378c2ecf20Sopenharmony_ci goto out; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci ret = file->f_op->fallocate(file, mode, pos, blk_rq_bytes(rq)); 4418c2ecf20Sopenharmony_ci if (unlikely(ret && ret != -EINVAL && ret != -EOPNOTSUPP)) 4428c2ecf20Sopenharmony_ci ret = -EIO; 4438c2ecf20Sopenharmony_ci out: 4448c2ecf20Sopenharmony_ci return ret; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic int lo_req_flush(struct loop_device *lo, struct request *rq) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct file *file = lo->lo_backing_file; 4508c2ecf20Sopenharmony_ci int ret = vfs_fsync(file, 0); 4518c2ecf20Sopenharmony_ci if (unlikely(ret && ret != -EINVAL)) 4528c2ecf20Sopenharmony_ci ret = -EIO; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci return ret; 4558c2ecf20Sopenharmony_ci} 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_cistatic void lo_complete_rq(struct request *rq) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq); 4608c2ecf20Sopenharmony_ci blk_status_t ret = BLK_STS_OK; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (!cmd->use_aio || cmd->ret < 0 || cmd->ret == blk_rq_bytes(rq) || 4638c2ecf20Sopenharmony_ci req_op(rq) != REQ_OP_READ) { 4648c2ecf20Sopenharmony_ci if (cmd->ret < 0) 4658c2ecf20Sopenharmony_ci ret = errno_to_blk_status(cmd->ret); 4668c2ecf20Sopenharmony_ci goto end_io; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* 4708c2ecf20Sopenharmony_ci * Short READ - if we got some data, advance our request and 4718c2ecf20Sopenharmony_ci * retry it. If we got no data, end the rest with EIO. 4728c2ecf20Sopenharmony_ci */ 4738c2ecf20Sopenharmony_ci if (cmd->ret) { 4748c2ecf20Sopenharmony_ci blk_update_request(rq, BLK_STS_OK, cmd->ret); 4758c2ecf20Sopenharmony_ci cmd->ret = 0; 4768c2ecf20Sopenharmony_ci blk_mq_requeue_request(rq, true); 4778c2ecf20Sopenharmony_ci } else { 4788c2ecf20Sopenharmony_ci if (cmd->use_aio) { 4798c2ecf20Sopenharmony_ci struct bio *bio = rq->bio; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci while (bio) { 4828c2ecf20Sopenharmony_ci zero_fill_bio(bio); 4838c2ecf20Sopenharmony_ci bio = bio->bi_next; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci ret = BLK_STS_IOERR; 4878c2ecf20Sopenharmony_ciend_io: 4888c2ecf20Sopenharmony_ci blk_mq_end_request(rq, ret); 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic void lo_rw_aio_do_completion(struct loop_cmd *cmd) 4938c2ecf20Sopenharmony_ci{ 4948c2ecf20Sopenharmony_ci struct request *rq = blk_mq_rq_from_pdu(cmd); 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (!atomic_dec_and_test(&cmd->ref)) 4978c2ecf20Sopenharmony_ci return; 4988c2ecf20Sopenharmony_ci kfree(cmd->bvec); 4998c2ecf20Sopenharmony_ci cmd->bvec = NULL; 5008c2ecf20Sopenharmony_ci if (likely(!blk_should_fake_timeout(rq->q))) 5018c2ecf20Sopenharmony_ci blk_mq_complete_request(rq); 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cistatic void lo_rw_aio_complete(struct kiocb *iocb, long ret, long ret2) 5058c2ecf20Sopenharmony_ci{ 5068c2ecf20Sopenharmony_ci struct loop_cmd *cmd = container_of(iocb, struct loop_cmd, iocb); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci if (cmd->css) 5098c2ecf20Sopenharmony_ci css_put(cmd->css); 5108c2ecf20Sopenharmony_ci cmd->ret = ret; 5118c2ecf20Sopenharmony_ci lo_rw_aio_do_completion(cmd); 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic int lo_rw_aio(struct loop_device *lo, struct loop_cmd *cmd, 5158c2ecf20Sopenharmony_ci loff_t pos, bool rw) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci struct iov_iter iter; 5188c2ecf20Sopenharmony_ci struct req_iterator rq_iter; 5198c2ecf20Sopenharmony_ci struct bio_vec *bvec; 5208c2ecf20Sopenharmony_ci struct request *rq = blk_mq_rq_from_pdu(cmd); 5218c2ecf20Sopenharmony_ci struct bio *bio = rq->bio; 5228c2ecf20Sopenharmony_ci struct file *file = lo->lo_backing_file; 5238c2ecf20Sopenharmony_ci struct bio_vec tmp; 5248c2ecf20Sopenharmony_ci unsigned int offset; 5258c2ecf20Sopenharmony_ci int nr_bvec = 0; 5268c2ecf20Sopenharmony_ci int ret; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci rq_for_each_bvec(tmp, rq, rq_iter) 5298c2ecf20Sopenharmony_ci nr_bvec++; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (rq->bio != rq->biotail) { 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci bvec = kmalloc_array(nr_bvec, sizeof(struct bio_vec), 5348c2ecf20Sopenharmony_ci GFP_NOIO); 5358c2ecf20Sopenharmony_ci if (!bvec) 5368c2ecf20Sopenharmony_ci return -EIO; 5378c2ecf20Sopenharmony_ci cmd->bvec = bvec; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci /* 5408c2ecf20Sopenharmony_ci * The bios of the request may be started from the middle of 5418c2ecf20Sopenharmony_ci * the 'bvec' because of bio splitting, so we can't directly 5428c2ecf20Sopenharmony_ci * copy bio->bi_iov_vec to new bvec. The rq_for_each_bvec 5438c2ecf20Sopenharmony_ci * API will take care of all details for us. 5448c2ecf20Sopenharmony_ci */ 5458c2ecf20Sopenharmony_ci rq_for_each_bvec(tmp, rq, rq_iter) { 5468c2ecf20Sopenharmony_ci *bvec = tmp; 5478c2ecf20Sopenharmony_ci bvec++; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci bvec = cmd->bvec; 5508c2ecf20Sopenharmony_ci offset = 0; 5518c2ecf20Sopenharmony_ci } else { 5528c2ecf20Sopenharmony_ci /* 5538c2ecf20Sopenharmony_ci * Same here, this bio may be started from the middle of the 5548c2ecf20Sopenharmony_ci * 'bvec' because of bio splitting, so offset from the bvec 5558c2ecf20Sopenharmony_ci * must be passed to iov iterator 5568c2ecf20Sopenharmony_ci */ 5578c2ecf20Sopenharmony_ci offset = bio->bi_iter.bi_bvec_done; 5588c2ecf20Sopenharmony_ci bvec = __bvec_iter_bvec(bio->bi_io_vec, bio->bi_iter); 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci atomic_set(&cmd->ref, 2); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci iov_iter_bvec(&iter, rw, bvec, nr_bvec, blk_rq_bytes(rq)); 5638c2ecf20Sopenharmony_ci iter.iov_offset = offset; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci cmd->iocb.ki_pos = pos; 5668c2ecf20Sopenharmony_ci cmd->iocb.ki_filp = file; 5678c2ecf20Sopenharmony_ci cmd->iocb.ki_complete = lo_rw_aio_complete; 5688c2ecf20Sopenharmony_ci cmd->iocb.ki_flags = IOCB_DIRECT; 5698c2ecf20Sopenharmony_ci cmd->iocb.ki_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, 0); 5708c2ecf20Sopenharmony_ci if (cmd->css) 5718c2ecf20Sopenharmony_ci kthread_associate_blkcg(cmd->css); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci if (rw == WRITE) 5748c2ecf20Sopenharmony_ci ret = call_write_iter(file, &cmd->iocb, &iter); 5758c2ecf20Sopenharmony_ci else 5768c2ecf20Sopenharmony_ci ret = call_read_iter(file, &cmd->iocb, &iter); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci lo_rw_aio_do_completion(cmd); 5798c2ecf20Sopenharmony_ci kthread_associate_blkcg(NULL); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (ret != -EIOCBQUEUED) 5828c2ecf20Sopenharmony_ci cmd->iocb.ki_complete(&cmd->iocb, ret, 0); 5838c2ecf20Sopenharmony_ci return 0; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic int do_req_filebacked(struct loop_device *lo, struct request *rq) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq); 5898c2ecf20Sopenharmony_ci loff_t pos = ((loff_t) blk_rq_pos(rq) << 9) + lo->lo_offset; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci /* 5928c2ecf20Sopenharmony_ci * lo_write_simple and lo_read_simple should have been covered 5938c2ecf20Sopenharmony_ci * by io submit style function like lo_rw_aio(), one blocker 5948c2ecf20Sopenharmony_ci * is that lo_read_simple() need to call flush_dcache_page after 5958c2ecf20Sopenharmony_ci * the page is written from kernel, and it isn't easy to handle 5968c2ecf20Sopenharmony_ci * this in io submit style function which submits all segments 5978c2ecf20Sopenharmony_ci * of the req at one time. And direct read IO doesn't need to 5988c2ecf20Sopenharmony_ci * run flush_dcache_page(). 5998c2ecf20Sopenharmony_ci */ 6008c2ecf20Sopenharmony_ci switch (req_op(rq)) { 6018c2ecf20Sopenharmony_ci case REQ_OP_FLUSH: 6028c2ecf20Sopenharmony_ci return lo_req_flush(lo, rq); 6038c2ecf20Sopenharmony_ci case REQ_OP_WRITE_ZEROES: 6048c2ecf20Sopenharmony_ci /* 6058c2ecf20Sopenharmony_ci * If the caller doesn't want deallocation, call zeroout to 6068c2ecf20Sopenharmony_ci * write zeroes the range. Otherwise, punch them out. 6078c2ecf20Sopenharmony_ci */ 6088c2ecf20Sopenharmony_ci return lo_fallocate(lo, rq, pos, 6098c2ecf20Sopenharmony_ci (rq->cmd_flags & REQ_NOUNMAP) ? 6108c2ecf20Sopenharmony_ci FALLOC_FL_ZERO_RANGE : 6118c2ecf20Sopenharmony_ci FALLOC_FL_PUNCH_HOLE); 6128c2ecf20Sopenharmony_ci case REQ_OP_DISCARD: 6138c2ecf20Sopenharmony_ci return lo_fallocate(lo, rq, pos, FALLOC_FL_PUNCH_HOLE); 6148c2ecf20Sopenharmony_ci case REQ_OP_WRITE: 6158c2ecf20Sopenharmony_ci if (lo->transfer) 6168c2ecf20Sopenharmony_ci return lo_write_transfer(lo, rq, pos); 6178c2ecf20Sopenharmony_ci else if (cmd->use_aio) 6188c2ecf20Sopenharmony_ci return lo_rw_aio(lo, cmd, pos, WRITE); 6198c2ecf20Sopenharmony_ci else 6208c2ecf20Sopenharmony_ci return lo_write_simple(lo, rq, pos); 6218c2ecf20Sopenharmony_ci case REQ_OP_READ: 6228c2ecf20Sopenharmony_ci if (lo->transfer) 6238c2ecf20Sopenharmony_ci return lo_read_transfer(lo, rq, pos); 6248c2ecf20Sopenharmony_ci else if (cmd->use_aio) 6258c2ecf20Sopenharmony_ci return lo_rw_aio(lo, cmd, pos, READ); 6268c2ecf20Sopenharmony_ci else 6278c2ecf20Sopenharmony_ci return lo_read_simple(lo, rq, pos); 6288c2ecf20Sopenharmony_ci default: 6298c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 6308c2ecf20Sopenharmony_ci return -EIO; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci} 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic inline void loop_update_dio(struct loop_device *lo) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci __loop_update_dio(lo, (lo->lo_backing_file->f_flags & O_DIRECT) | 6378c2ecf20Sopenharmony_ci lo->use_dio); 6388c2ecf20Sopenharmony_ci} 6398c2ecf20Sopenharmony_ci 6408c2ecf20Sopenharmony_cistatic void loop_reread_partitions(struct loop_device *lo, 6418c2ecf20Sopenharmony_ci struct block_device *bdev) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci int rc; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci mutex_lock(&bdev->bd_mutex); 6468c2ecf20Sopenharmony_ci rc = bdev_disk_changed(bdev, false); 6478c2ecf20Sopenharmony_ci mutex_unlock(&bdev->bd_mutex); 6488c2ecf20Sopenharmony_ci if (rc) 6498c2ecf20Sopenharmony_ci pr_warn("%s: partition scan of loop%d (%s) failed (rc=%d)\n", 6508c2ecf20Sopenharmony_ci __func__, lo->lo_number, lo->lo_file_name, rc); 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_cistatic inline int is_loop_device(struct file *file) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci struct inode *i = file->f_mapping->host; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic int loop_validate_file(struct file *file, struct block_device *bdev) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci struct inode *inode = file->f_mapping->host; 6638c2ecf20Sopenharmony_ci struct file *f = file; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci /* Avoid recursion */ 6668c2ecf20Sopenharmony_ci while (is_loop_device(f)) { 6678c2ecf20Sopenharmony_ci struct loop_device *l; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci if (f->f_mapping->host->i_bdev == bdev) 6708c2ecf20Sopenharmony_ci return -EBADF; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci l = f->f_mapping->host->i_bdev->bd_disk->private_data; 6738c2ecf20Sopenharmony_ci if (l->lo_state != Lo_bound) { 6748c2ecf20Sopenharmony_ci return -EINVAL; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci f = l->lo_backing_file; 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) 6798c2ecf20Sopenharmony_ci return -EINVAL; 6808c2ecf20Sopenharmony_ci return 0; 6818c2ecf20Sopenharmony_ci} 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci/* 6848c2ecf20Sopenharmony_ci * loop_change_fd switched the backing store of a loopback device to 6858c2ecf20Sopenharmony_ci * a new file. This is useful for operating system installers to free up 6868c2ecf20Sopenharmony_ci * the original file and in High Availability environments to switch to 6878c2ecf20Sopenharmony_ci * an alternative location for the content in case of server meltdown. 6888c2ecf20Sopenharmony_ci * This can only work if the loop device is used read-only, and if the 6898c2ecf20Sopenharmony_ci * new backing store is the same size and type as the old backing store. 6908c2ecf20Sopenharmony_ci */ 6918c2ecf20Sopenharmony_cistatic int loop_change_fd(struct loop_device *lo, struct block_device *bdev, 6928c2ecf20Sopenharmony_ci unsigned int arg) 6938c2ecf20Sopenharmony_ci{ 6948c2ecf20Sopenharmony_ci struct file *file = NULL, *old_file; 6958c2ecf20Sopenharmony_ci int error; 6968c2ecf20Sopenharmony_ci bool partscan; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci error = mutex_lock_killable(&loop_ctl_mutex); 6998c2ecf20Sopenharmony_ci if (error) 7008c2ecf20Sopenharmony_ci return error; 7018c2ecf20Sopenharmony_ci error = -ENXIO; 7028c2ecf20Sopenharmony_ci if (lo->lo_state != Lo_bound) 7038c2ecf20Sopenharmony_ci goto out_err; 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci /* the loop device has to be read-only */ 7068c2ecf20Sopenharmony_ci error = -EINVAL; 7078c2ecf20Sopenharmony_ci if (!(lo->lo_flags & LO_FLAGS_READ_ONLY)) 7088c2ecf20Sopenharmony_ci goto out_err; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci error = -EBADF; 7118c2ecf20Sopenharmony_ci file = fget(arg); 7128c2ecf20Sopenharmony_ci if (!file) 7138c2ecf20Sopenharmony_ci goto out_err; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci error = loop_validate_file(file, bdev); 7168c2ecf20Sopenharmony_ci if (error) 7178c2ecf20Sopenharmony_ci goto out_err; 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_ci old_file = lo->lo_backing_file; 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci error = -EINVAL; 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci /* size of the new backing store needs to be the same */ 7248c2ecf20Sopenharmony_ci if (get_loop_size(lo, file) != get_loop_size(lo, old_file)) 7258c2ecf20Sopenharmony_ci goto out_err; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci /* and ... switch */ 7288c2ecf20Sopenharmony_ci blk_mq_freeze_queue(lo->lo_queue); 7298c2ecf20Sopenharmony_ci mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask); 7308c2ecf20Sopenharmony_ci lo->lo_backing_file = file; 7318c2ecf20Sopenharmony_ci lo->old_gfp_mask = mapping_gfp_mask(file->f_mapping); 7328c2ecf20Sopenharmony_ci mapping_set_gfp_mask(file->f_mapping, 7338c2ecf20Sopenharmony_ci lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); 7348c2ecf20Sopenharmony_ci loop_update_dio(lo); 7358c2ecf20Sopenharmony_ci blk_mq_unfreeze_queue(lo->lo_queue); 7368c2ecf20Sopenharmony_ci partscan = lo->lo_flags & LO_FLAGS_PARTSCAN; 7378c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 7388c2ecf20Sopenharmony_ci /* 7398c2ecf20Sopenharmony_ci * We must drop file reference outside of loop_ctl_mutex as dropping 7408c2ecf20Sopenharmony_ci * the file ref can take bd_mutex which creates circular locking 7418c2ecf20Sopenharmony_ci * dependency. 7428c2ecf20Sopenharmony_ci */ 7438c2ecf20Sopenharmony_ci fput(old_file); 7448c2ecf20Sopenharmony_ci if (partscan) 7458c2ecf20Sopenharmony_ci loop_reread_partitions(lo, bdev); 7468c2ecf20Sopenharmony_ci return 0; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ciout_err: 7498c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 7508c2ecf20Sopenharmony_ci if (file) 7518c2ecf20Sopenharmony_ci fput(file); 7528c2ecf20Sopenharmony_ci return error; 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci/* loop sysfs attributes */ 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_cistatic ssize_t loop_attr_show(struct device *dev, char *page, 7588c2ecf20Sopenharmony_ci ssize_t (*callback)(struct loop_device *, char *)) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct gendisk *disk = dev_to_disk(dev); 7618c2ecf20Sopenharmony_ci struct loop_device *lo = disk->private_data; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci return callback(lo, page); 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci#define LOOP_ATTR_RO(_name) \ 7678c2ecf20Sopenharmony_cistatic ssize_t loop_attr_##_name##_show(struct loop_device *, char *); \ 7688c2ecf20Sopenharmony_cistatic ssize_t loop_attr_do_show_##_name(struct device *d, \ 7698c2ecf20Sopenharmony_ci struct device_attribute *attr, char *b) \ 7708c2ecf20Sopenharmony_ci{ \ 7718c2ecf20Sopenharmony_ci return loop_attr_show(d, b, loop_attr_##_name##_show); \ 7728c2ecf20Sopenharmony_ci} \ 7738c2ecf20Sopenharmony_cistatic struct device_attribute loop_attr_##_name = \ 7748c2ecf20Sopenharmony_ci __ATTR(_name, 0444, loop_attr_do_show_##_name, NULL); 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_cistatic ssize_t loop_attr_backing_file_show(struct loop_device *lo, char *buf) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci ssize_t ret; 7798c2ecf20Sopenharmony_ci char *p = NULL; 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci spin_lock_irq(&lo->lo_lock); 7828c2ecf20Sopenharmony_ci if (lo->lo_backing_file) 7838c2ecf20Sopenharmony_ci p = file_path(lo->lo_backing_file, buf, PAGE_SIZE - 1); 7848c2ecf20Sopenharmony_ci spin_unlock_irq(&lo->lo_lock); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci if (IS_ERR_OR_NULL(p)) 7878c2ecf20Sopenharmony_ci ret = PTR_ERR(p); 7888c2ecf20Sopenharmony_ci else { 7898c2ecf20Sopenharmony_ci ret = strlen(p); 7908c2ecf20Sopenharmony_ci memmove(buf, p, ret); 7918c2ecf20Sopenharmony_ci buf[ret++] = '\n'; 7928c2ecf20Sopenharmony_ci buf[ret] = 0; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci return ret; 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic ssize_t loop_attr_offset_show(struct loop_device *lo, char *buf) 7998c2ecf20Sopenharmony_ci{ 8008c2ecf20Sopenharmony_ci return sysfs_emit(buf, "%llu\n", (unsigned long long)lo->lo_offset); 8018c2ecf20Sopenharmony_ci} 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistatic ssize_t loop_attr_sizelimit_show(struct loop_device *lo, char *buf) 8048c2ecf20Sopenharmony_ci{ 8058c2ecf20Sopenharmony_ci return sysfs_emit(buf, "%llu\n", (unsigned long long)lo->lo_sizelimit); 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic ssize_t loop_attr_autoclear_show(struct loop_device *lo, char *buf) 8098c2ecf20Sopenharmony_ci{ 8108c2ecf20Sopenharmony_ci int autoclear = (lo->lo_flags & LO_FLAGS_AUTOCLEAR); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci return sysfs_emit(buf, "%s\n", autoclear ? "1" : "0"); 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic ssize_t loop_attr_partscan_show(struct loop_device *lo, char *buf) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci int partscan = (lo->lo_flags & LO_FLAGS_PARTSCAN); 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci return sysfs_emit(buf, "%s\n", partscan ? "1" : "0"); 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_cistatic ssize_t loop_attr_dio_show(struct loop_device *lo, char *buf) 8238c2ecf20Sopenharmony_ci{ 8248c2ecf20Sopenharmony_ci int dio = (lo->lo_flags & LO_FLAGS_DIRECT_IO); 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_ci return sysfs_emit(buf, "%s\n", dio ? "1" : "0"); 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ciLOOP_ATTR_RO(backing_file); 8308c2ecf20Sopenharmony_ciLOOP_ATTR_RO(offset); 8318c2ecf20Sopenharmony_ciLOOP_ATTR_RO(sizelimit); 8328c2ecf20Sopenharmony_ciLOOP_ATTR_RO(autoclear); 8338c2ecf20Sopenharmony_ciLOOP_ATTR_RO(partscan); 8348c2ecf20Sopenharmony_ciLOOP_ATTR_RO(dio); 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_cistatic struct attribute *loop_attrs[] = { 8378c2ecf20Sopenharmony_ci &loop_attr_backing_file.attr, 8388c2ecf20Sopenharmony_ci &loop_attr_offset.attr, 8398c2ecf20Sopenharmony_ci &loop_attr_sizelimit.attr, 8408c2ecf20Sopenharmony_ci &loop_attr_autoclear.attr, 8418c2ecf20Sopenharmony_ci &loop_attr_partscan.attr, 8428c2ecf20Sopenharmony_ci &loop_attr_dio.attr, 8438c2ecf20Sopenharmony_ci NULL, 8448c2ecf20Sopenharmony_ci}; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_cistatic struct attribute_group loop_attribute_group = { 8478c2ecf20Sopenharmony_ci .name = "loop", 8488c2ecf20Sopenharmony_ci .attrs= loop_attrs, 8498c2ecf20Sopenharmony_ci}; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_cistatic void loop_sysfs_init(struct loop_device *lo) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci lo->sysfs_inited = !sysfs_create_group(&disk_to_dev(lo->lo_disk)->kobj, 8548c2ecf20Sopenharmony_ci &loop_attribute_group); 8558c2ecf20Sopenharmony_ci} 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_cistatic void loop_sysfs_exit(struct loop_device *lo) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci if (lo->sysfs_inited) 8608c2ecf20Sopenharmony_ci sysfs_remove_group(&disk_to_dev(lo->lo_disk)->kobj, 8618c2ecf20Sopenharmony_ci &loop_attribute_group); 8628c2ecf20Sopenharmony_ci} 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_cistatic void loop_config_discard(struct loop_device *lo) 8658c2ecf20Sopenharmony_ci{ 8668c2ecf20Sopenharmony_ci struct file *file = lo->lo_backing_file; 8678c2ecf20Sopenharmony_ci struct inode *inode = file->f_mapping->host; 8688c2ecf20Sopenharmony_ci struct request_queue *q = lo->lo_queue; 8698c2ecf20Sopenharmony_ci u32 granularity, max_discard_sectors; 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci /* 8728c2ecf20Sopenharmony_ci * If the backing device is a block device, mirror its zeroing 8738c2ecf20Sopenharmony_ci * capability. Set the discard sectors to the block device's zeroing 8748c2ecf20Sopenharmony_ci * capabilities because loop discards result in blkdev_issue_zeroout(), 8758c2ecf20Sopenharmony_ci * not blkdev_issue_discard(). This maintains consistent behavior with 8768c2ecf20Sopenharmony_ci * file-backed loop devices: discarded regions read back as zero. 8778c2ecf20Sopenharmony_ci */ 8788c2ecf20Sopenharmony_ci if (S_ISBLK(inode->i_mode) && !lo->lo_encrypt_key_size) { 8798c2ecf20Sopenharmony_ci struct request_queue *backingq; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci backingq = bdev_get_queue(inode->i_bdev); 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci max_discard_sectors = backingq->limits.max_write_zeroes_sectors; 8848c2ecf20Sopenharmony_ci granularity = backingq->limits.discard_granularity ?: 8858c2ecf20Sopenharmony_ci queue_physical_block_size(backingq); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci /* 8888c2ecf20Sopenharmony_ci * We use punch hole to reclaim the free space used by the 8898c2ecf20Sopenharmony_ci * image a.k.a. discard. However we do not support discard if 8908c2ecf20Sopenharmony_ci * encryption is enabled, because it may give an attacker 8918c2ecf20Sopenharmony_ci * useful information. 8928c2ecf20Sopenharmony_ci */ 8938c2ecf20Sopenharmony_ci } else if (!file->f_op->fallocate || lo->lo_encrypt_key_size) { 8948c2ecf20Sopenharmony_ci max_discard_sectors = 0; 8958c2ecf20Sopenharmony_ci granularity = 0; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci } else { 8988c2ecf20Sopenharmony_ci max_discard_sectors = UINT_MAX >> 9; 8998c2ecf20Sopenharmony_ci granularity = inode->i_sb->s_blocksize; 9008c2ecf20Sopenharmony_ci } 9018c2ecf20Sopenharmony_ci 9028c2ecf20Sopenharmony_ci if (max_discard_sectors) { 9038c2ecf20Sopenharmony_ci q->limits.discard_granularity = granularity; 9048c2ecf20Sopenharmony_ci blk_queue_max_discard_sectors(q, max_discard_sectors); 9058c2ecf20Sopenharmony_ci blk_queue_max_write_zeroes_sectors(q, max_discard_sectors); 9068c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_DISCARD, q); 9078c2ecf20Sopenharmony_ci } else { 9088c2ecf20Sopenharmony_ci q->limits.discard_granularity = 0; 9098c2ecf20Sopenharmony_ci blk_queue_max_discard_sectors(q, 0); 9108c2ecf20Sopenharmony_ci blk_queue_max_write_zeroes_sectors(q, 0); 9118c2ecf20Sopenharmony_ci blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q); 9128c2ecf20Sopenharmony_ci } 9138c2ecf20Sopenharmony_ci q->limits.discard_alignment = 0; 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cistatic void loop_unprepare_queue(struct loop_device *lo) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci kthread_flush_worker(&lo->worker); 9198c2ecf20Sopenharmony_ci kthread_stop(lo->worker_task); 9208c2ecf20Sopenharmony_ci} 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cistatic int loop_kthread_worker_fn(void *worker_ptr) 9238c2ecf20Sopenharmony_ci{ 9248c2ecf20Sopenharmony_ci current->flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO; 9258c2ecf20Sopenharmony_ci return kthread_worker_fn(worker_ptr); 9268c2ecf20Sopenharmony_ci} 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_cistatic int loop_prepare_queue(struct loop_device *lo) 9298c2ecf20Sopenharmony_ci{ 9308c2ecf20Sopenharmony_ci kthread_init_worker(&lo->worker); 9318c2ecf20Sopenharmony_ci lo->worker_task = kthread_run(loop_kthread_worker_fn, 9328c2ecf20Sopenharmony_ci &lo->worker, "loop%d", lo->lo_number); 9338c2ecf20Sopenharmony_ci if (IS_ERR(lo->worker_task)) 9348c2ecf20Sopenharmony_ci return -ENOMEM; 9358c2ecf20Sopenharmony_ci set_user_nice(lo->worker_task, MIN_NICE); 9368c2ecf20Sopenharmony_ci return 0; 9378c2ecf20Sopenharmony_ci} 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_cistatic void loop_update_rotational(struct loop_device *lo) 9408c2ecf20Sopenharmony_ci{ 9418c2ecf20Sopenharmony_ci struct file *file = lo->lo_backing_file; 9428c2ecf20Sopenharmony_ci struct inode *file_inode = file->f_mapping->host; 9438c2ecf20Sopenharmony_ci struct block_device *file_bdev = file_inode->i_sb->s_bdev; 9448c2ecf20Sopenharmony_ci struct request_queue *q = lo->lo_queue; 9458c2ecf20Sopenharmony_ci bool nonrot = true; 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_ci /* not all filesystems (e.g. tmpfs) have a sb->s_bdev */ 9488c2ecf20Sopenharmony_ci if (file_bdev) 9498c2ecf20Sopenharmony_ci nonrot = blk_queue_nonrot(bdev_get_queue(file_bdev)); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci if (nonrot) 9528c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_NONROT, q); 9538c2ecf20Sopenharmony_ci else 9548c2ecf20Sopenharmony_ci blk_queue_flag_clear(QUEUE_FLAG_NONROT, q); 9558c2ecf20Sopenharmony_ci} 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_cistatic int 9588c2ecf20Sopenharmony_ciloop_release_xfer(struct loop_device *lo) 9598c2ecf20Sopenharmony_ci{ 9608c2ecf20Sopenharmony_ci int err = 0; 9618c2ecf20Sopenharmony_ci struct loop_func_table *xfer = lo->lo_encryption; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci if (xfer) { 9648c2ecf20Sopenharmony_ci if (xfer->release) 9658c2ecf20Sopenharmony_ci err = xfer->release(lo); 9668c2ecf20Sopenharmony_ci lo->transfer = NULL; 9678c2ecf20Sopenharmony_ci lo->lo_encryption = NULL; 9688c2ecf20Sopenharmony_ci module_put(xfer->owner); 9698c2ecf20Sopenharmony_ci } 9708c2ecf20Sopenharmony_ci return err; 9718c2ecf20Sopenharmony_ci} 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_cistatic int 9748c2ecf20Sopenharmony_ciloop_init_xfer(struct loop_device *lo, struct loop_func_table *xfer, 9758c2ecf20Sopenharmony_ci const struct loop_info64 *i) 9768c2ecf20Sopenharmony_ci{ 9778c2ecf20Sopenharmony_ci int err = 0; 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci if (xfer) { 9808c2ecf20Sopenharmony_ci struct module *owner = xfer->owner; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci if (!try_module_get(owner)) 9838c2ecf20Sopenharmony_ci return -EINVAL; 9848c2ecf20Sopenharmony_ci if (xfer->init) 9858c2ecf20Sopenharmony_ci err = xfer->init(lo, i); 9868c2ecf20Sopenharmony_ci if (err) 9878c2ecf20Sopenharmony_ci module_put(owner); 9888c2ecf20Sopenharmony_ci else 9898c2ecf20Sopenharmony_ci lo->lo_encryption = xfer; 9908c2ecf20Sopenharmony_ci } 9918c2ecf20Sopenharmony_ci return err; 9928c2ecf20Sopenharmony_ci} 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci/** 9958c2ecf20Sopenharmony_ci * loop_set_status_from_info - configure device from loop_info 9968c2ecf20Sopenharmony_ci * @lo: struct loop_device to configure 9978c2ecf20Sopenharmony_ci * @info: struct loop_info64 to configure the device with 9988c2ecf20Sopenharmony_ci * 9998c2ecf20Sopenharmony_ci * Configures the loop device parameters according to the passed 10008c2ecf20Sopenharmony_ci * in loop_info64 configuration. 10018c2ecf20Sopenharmony_ci */ 10028c2ecf20Sopenharmony_cistatic int 10038c2ecf20Sopenharmony_ciloop_set_status_from_info(struct loop_device *lo, 10048c2ecf20Sopenharmony_ci const struct loop_info64 *info) 10058c2ecf20Sopenharmony_ci{ 10068c2ecf20Sopenharmony_ci int err; 10078c2ecf20Sopenharmony_ci struct loop_func_table *xfer; 10088c2ecf20Sopenharmony_ci kuid_t uid = current_uid(); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci if ((unsigned int) info->lo_encrypt_key_size > LO_KEY_SIZE) 10118c2ecf20Sopenharmony_ci return -EINVAL; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci err = loop_release_xfer(lo); 10148c2ecf20Sopenharmony_ci if (err) 10158c2ecf20Sopenharmony_ci return err; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci if (info->lo_encrypt_type) { 10188c2ecf20Sopenharmony_ci unsigned int type = info->lo_encrypt_type; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci if (type >= MAX_LO_CRYPT) 10218c2ecf20Sopenharmony_ci return -EINVAL; 10228c2ecf20Sopenharmony_ci xfer = xfer_funcs[type]; 10238c2ecf20Sopenharmony_ci if (xfer == NULL) 10248c2ecf20Sopenharmony_ci return -EINVAL; 10258c2ecf20Sopenharmony_ci } else 10268c2ecf20Sopenharmony_ci xfer = NULL; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci err = loop_init_xfer(lo, xfer, info); 10298c2ecf20Sopenharmony_ci if (err) 10308c2ecf20Sopenharmony_ci return err; 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci /* Avoid assigning overflow values */ 10338c2ecf20Sopenharmony_ci if (info->lo_offset > LLONG_MAX || info->lo_sizelimit > LLONG_MAX) 10348c2ecf20Sopenharmony_ci return -EOVERFLOW; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci lo->lo_offset = info->lo_offset; 10378c2ecf20Sopenharmony_ci lo->lo_sizelimit = info->lo_sizelimit; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci memcpy(lo->lo_file_name, info->lo_file_name, LO_NAME_SIZE); 10408c2ecf20Sopenharmony_ci memcpy(lo->lo_crypt_name, info->lo_crypt_name, LO_NAME_SIZE); 10418c2ecf20Sopenharmony_ci lo->lo_file_name[LO_NAME_SIZE-1] = 0; 10428c2ecf20Sopenharmony_ci lo->lo_crypt_name[LO_NAME_SIZE-1] = 0; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci if (!xfer) 10458c2ecf20Sopenharmony_ci xfer = &none_funcs; 10468c2ecf20Sopenharmony_ci lo->transfer = xfer->transfer; 10478c2ecf20Sopenharmony_ci lo->ioctl = xfer->ioctl; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci lo->lo_flags = info->lo_flags; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci lo->lo_encrypt_key_size = info->lo_encrypt_key_size; 10528c2ecf20Sopenharmony_ci lo->lo_init[0] = info->lo_init[0]; 10538c2ecf20Sopenharmony_ci lo->lo_init[1] = info->lo_init[1]; 10548c2ecf20Sopenharmony_ci if (info->lo_encrypt_key_size) { 10558c2ecf20Sopenharmony_ci memcpy(lo->lo_encrypt_key, info->lo_encrypt_key, 10568c2ecf20Sopenharmony_ci info->lo_encrypt_key_size); 10578c2ecf20Sopenharmony_ci lo->lo_key_owner = uid; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ci return 0; 10618c2ecf20Sopenharmony_ci} 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_cistatic int loop_configure(struct loop_device *lo, fmode_t mode, 10648c2ecf20Sopenharmony_ci struct block_device *bdev, 10658c2ecf20Sopenharmony_ci const struct loop_config *config) 10668c2ecf20Sopenharmony_ci{ 10678c2ecf20Sopenharmony_ci struct file *file; 10688c2ecf20Sopenharmony_ci struct inode *inode; 10698c2ecf20Sopenharmony_ci struct address_space *mapping; 10708c2ecf20Sopenharmony_ci struct block_device *claimed_bdev = NULL; 10718c2ecf20Sopenharmony_ci int error; 10728c2ecf20Sopenharmony_ci loff_t size; 10738c2ecf20Sopenharmony_ci bool partscan; 10748c2ecf20Sopenharmony_ci unsigned short bsize; 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci /* This is safe, since we have a reference from open(). */ 10778c2ecf20Sopenharmony_ci __module_get(THIS_MODULE); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci error = -EBADF; 10808c2ecf20Sopenharmony_ci file = fget(config->fd); 10818c2ecf20Sopenharmony_ci if (!file) 10828c2ecf20Sopenharmony_ci goto out; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci /* 10858c2ecf20Sopenharmony_ci * If we don't hold exclusive handle for the device, upgrade to it 10868c2ecf20Sopenharmony_ci * here to avoid changing device under exclusive owner. 10878c2ecf20Sopenharmony_ci */ 10888c2ecf20Sopenharmony_ci if (!(mode & FMODE_EXCL)) { 10898c2ecf20Sopenharmony_ci claimed_bdev = bdev->bd_contains; 10908c2ecf20Sopenharmony_ci error = bd_prepare_to_claim(bdev, claimed_bdev, loop_configure); 10918c2ecf20Sopenharmony_ci if (error) 10928c2ecf20Sopenharmony_ci goto out_putf; 10938c2ecf20Sopenharmony_ci } 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci error = mutex_lock_killable(&loop_ctl_mutex); 10968c2ecf20Sopenharmony_ci if (error) 10978c2ecf20Sopenharmony_ci goto out_bdev; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci error = -EBUSY; 11008c2ecf20Sopenharmony_ci if (lo->lo_state != Lo_unbound) 11018c2ecf20Sopenharmony_ci goto out_unlock; 11028c2ecf20Sopenharmony_ci 11038c2ecf20Sopenharmony_ci error = loop_validate_file(file, bdev); 11048c2ecf20Sopenharmony_ci if (error) 11058c2ecf20Sopenharmony_ci goto out_unlock; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci mapping = file->f_mapping; 11088c2ecf20Sopenharmony_ci inode = mapping->host; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci if ((config->info.lo_flags & ~LOOP_CONFIGURE_SETTABLE_FLAGS) != 0) { 11118c2ecf20Sopenharmony_ci error = -EINVAL; 11128c2ecf20Sopenharmony_ci goto out_unlock; 11138c2ecf20Sopenharmony_ci } 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci if (config->block_size) { 11168c2ecf20Sopenharmony_ci error = blk_validate_block_size(config->block_size); 11178c2ecf20Sopenharmony_ci if (error) 11188c2ecf20Sopenharmony_ci goto out_unlock; 11198c2ecf20Sopenharmony_ci } 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci error = loop_set_status_from_info(lo, &config->info); 11228c2ecf20Sopenharmony_ci if (error) 11238c2ecf20Sopenharmony_ci goto out_unlock; 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci if (!(file->f_mode & FMODE_WRITE) || !(mode & FMODE_WRITE) || 11268c2ecf20Sopenharmony_ci !file->f_op->write_iter) 11278c2ecf20Sopenharmony_ci lo->lo_flags |= LO_FLAGS_READ_ONLY; 11288c2ecf20Sopenharmony_ci 11298c2ecf20Sopenharmony_ci error = loop_prepare_queue(lo); 11308c2ecf20Sopenharmony_ci if (error) 11318c2ecf20Sopenharmony_ci goto out_unlock; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci set_device_ro(bdev, (lo->lo_flags & LO_FLAGS_READ_ONLY) != 0); 11348c2ecf20Sopenharmony_ci 11358c2ecf20Sopenharmony_ci lo->use_dio = lo->lo_flags & LO_FLAGS_DIRECT_IO; 11368c2ecf20Sopenharmony_ci lo->lo_device = bdev; 11378c2ecf20Sopenharmony_ci lo->lo_backing_file = file; 11388c2ecf20Sopenharmony_ci lo->old_gfp_mask = mapping_gfp_mask(mapping); 11398c2ecf20Sopenharmony_ci mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS)); 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci if (!(lo->lo_flags & LO_FLAGS_READ_ONLY) && file->f_op->fsync) 11428c2ecf20Sopenharmony_ci blk_queue_write_cache(lo->lo_queue, true, false); 11438c2ecf20Sopenharmony_ci 11448c2ecf20Sopenharmony_ci if (config->block_size) 11458c2ecf20Sopenharmony_ci bsize = config->block_size; 11468c2ecf20Sopenharmony_ci else if ((lo->lo_backing_file->f_flags & O_DIRECT) && inode->i_sb->s_bdev) 11478c2ecf20Sopenharmony_ci /* In case of direct I/O, match underlying block size */ 11488c2ecf20Sopenharmony_ci bsize = bdev_logical_block_size(inode->i_sb->s_bdev); 11498c2ecf20Sopenharmony_ci else 11508c2ecf20Sopenharmony_ci bsize = 512; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci blk_queue_logical_block_size(lo->lo_queue, bsize); 11538c2ecf20Sopenharmony_ci blk_queue_physical_block_size(lo->lo_queue, bsize); 11548c2ecf20Sopenharmony_ci blk_queue_io_min(lo->lo_queue, bsize); 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci loop_config_discard(lo); 11578c2ecf20Sopenharmony_ci loop_update_rotational(lo); 11588c2ecf20Sopenharmony_ci loop_update_dio(lo); 11598c2ecf20Sopenharmony_ci loop_sysfs_init(lo); 11608c2ecf20Sopenharmony_ci 11618c2ecf20Sopenharmony_ci size = get_loop_size(lo, file); 11628c2ecf20Sopenharmony_ci loop_set_size(lo, size); 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci set_blocksize(bdev, S_ISBLK(inode->i_mode) ? 11658c2ecf20Sopenharmony_ci block_size(inode->i_bdev) : PAGE_SIZE); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci lo->lo_state = Lo_bound; 11688c2ecf20Sopenharmony_ci if (part_shift) 11698c2ecf20Sopenharmony_ci lo->lo_flags |= LO_FLAGS_PARTSCAN; 11708c2ecf20Sopenharmony_ci partscan = lo->lo_flags & LO_FLAGS_PARTSCAN; 11718c2ecf20Sopenharmony_ci if (partscan) 11728c2ecf20Sopenharmony_ci lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci /* Grab the block_device to prevent its destruction after we 11758c2ecf20Sopenharmony_ci * put /dev/loopXX inode. Later in __loop_clr_fd() we bdput(bdev). 11768c2ecf20Sopenharmony_ci */ 11778c2ecf20Sopenharmony_ci bdgrab(bdev); 11788c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 11798c2ecf20Sopenharmony_ci if (partscan) 11808c2ecf20Sopenharmony_ci loop_reread_partitions(lo, bdev); 11818c2ecf20Sopenharmony_ci if (claimed_bdev) 11828c2ecf20Sopenharmony_ci bd_abort_claiming(bdev, claimed_bdev, loop_configure); 11838c2ecf20Sopenharmony_ci return 0; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ciout_unlock: 11868c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 11878c2ecf20Sopenharmony_ciout_bdev: 11888c2ecf20Sopenharmony_ci if (claimed_bdev) 11898c2ecf20Sopenharmony_ci bd_abort_claiming(bdev, claimed_bdev, loop_configure); 11908c2ecf20Sopenharmony_ciout_putf: 11918c2ecf20Sopenharmony_ci fput(file); 11928c2ecf20Sopenharmony_ciout: 11938c2ecf20Sopenharmony_ci /* This is safe: open() is still holding a reference. */ 11948c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 11958c2ecf20Sopenharmony_ci return error; 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_cistatic int __loop_clr_fd(struct loop_device *lo, bool release) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci struct file *filp = NULL; 12018c2ecf20Sopenharmony_ci gfp_t gfp = lo->old_gfp_mask; 12028c2ecf20Sopenharmony_ci struct block_device *bdev = lo->lo_device; 12038c2ecf20Sopenharmony_ci int err = 0; 12048c2ecf20Sopenharmony_ci bool partscan = false; 12058c2ecf20Sopenharmony_ci int lo_number; 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci mutex_lock(&loop_ctl_mutex); 12088c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(lo->lo_state != Lo_rundown)) { 12098c2ecf20Sopenharmony_ci err = -ENXIO; 12108c2ecf20Sopenharmony_ci goto out_unlock; 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci filp = lo->lo_backing_file; 12148c2ecf20Sopenharmony_ci if (filp == NULL) { 12158c2ecf20Sopenharmony_ci err = -EINVAL; 12168c2ecf20Sopenharmony_ci goto out_unlock; 12178c2ecf20Sopenharmony_ci } 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci if (test_bit(QUEUE_FLAG_WC, &lo->lo_queue->queue_flags)) 12208c2ecf20Sopenharmony_ci blk_queue_write_cache(lo->lo_queue, false, false); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci /* freeze request queue during the transition */ 12238c2ecf20Sopenharmony_ci blk_mq_freeze_queue(lo->lo_queue); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci spin_lock_irq(&lo->lo_lock); 12268c2ecf20Sopenharmony_ci lo->lo_backing_file = NULL; 12278c2ecf20Sopenharmony_ci spin_unlock_irq(&lo->lo_lock); 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci loop_release_xfer(lo); 12308c2ecf20Sopenharmony_ci lo->transfer = NULL; 12318c2ecf20Sopenharmony_ci lo->ioctl = NULL; 12328c2ecf20Sopenharmony_ci lo->lo_device = NULL; 12338c2ecf20Sopenharmony_ci lo->lo_encryption = NULL; 12348c2ecf20Sopenharmony_ci lo->lo_offset = 0; 12358c2ecf20Sopenharmony_ci lo->lo_sizelimit = 0; 12368c2ecf20Sopenharmony_ci lo->lo_encrypt_key_size = 0; 12378c2ecf20Sopenharmony_ci memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); 12388c2ecf20Sopenharmony_ci memset(lo->lo_crypt_name, 0, LO_NAME_SIZE); 12398c2ecf20Sopenharmony_ci memset(lo->lo_file_name, 0, LO_NAME_SIZE); 12408c2ecf20Sopenharmony_ci blk_queue_logical_block_size(lo->lo_queue, 512); 12418c2ecf20Sopenharmony_ci blk_queue_physical_block_size(lo->lo_queue, 512); 12428c2ecf20Sopenharmony_ci blk_queue_io_min(lo->lo_queue, 512); 12438c2ecf20Sopenharmony_ci if (bdev) { 12448c2ecf20Sopenharmony_ci bdput(bdev); 12458c2ecf20Sopenharmony_ci invalidate_bdev(bdev); 12468c2ecf20Sopenharmony_ci bdev->bd_inode->i_mapping->wb_err = 0; 12478c2ecf20Sopenharmony_ci } 12488c2ecf20Sopenharmony_ci set_capacity(lo->lo_disk, 0); 12498c2ecf20Sopenharmony_ci loop_sysfs_exit(lo); 12508c2ecf20Sopenharmony_ci if (bdev) { 12518c2ecf20Sopenharmony_ci bd_set_nr_sectors(bdev, 0); 12528c2ecf20Sopenharmony_ci /* let user-space know about this change */ 12538c2ecf20Sopenharmony_ci kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE); 12548c2ecf20Sopenharmony_ci } 12558c2ecf20Sopenharmony_ci mapping_set_gfp_mask(filp->f_mapping, gfp); 12568c2ecf20Sopenharmony_ci /* This is safe: open() is still holding a reference. */ 12578c2ecf20Sopenharmony_ci module_put(THIS_MODULE); 12588c2ecf20Sopenharmony_ci blk_mq_unfreeze_queue(lo->lo_queue); 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci partscan = lo->lo_flags & LO_FLAGS_PARTSCAN && bdev; 12618c2ecf20Sopenharmony_ci lo_number = lo->lo_number; 12628c2ecf20Sopenharmony_ci loop_unprepare_queue(lo); 12638c2ecf20Sopenharmony_ciout_unlock: 12648c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 12658c2ecf20Sopenharmony_ci if (partscan) { 12668c2ecf20Sopenharmony_ci /* 12678c2ecf20Sopenharmony_ci * bd_mutex has been held already in release path, so don't 12688c2ecf20Sopenharmony_ci * acquire it if this function is called in such case. 12698c2ecf20Sopenharmony_ci * 12708c2ecf20Sopenharmony_ci * If the reread partition isn't from release path, lo_refcnt 12718c2ecf20Sopenharmony_ci * must be at least one and it can only become zero when the 12728c2ecf20Sopenharmony_ci * current holder is released. 12738c2ecf20Sopenharmony_ci */ 12748c2ecf20Sopenharmony_ci if (!release) 12758c2ecf20Sopenharmony_ci mutex_lock(&bdev->bd_mutex); 12768c2ecf20Sopenharmony_ci err = bdev_disk_changed(bdev, false); 12778c2ecf20Sopenharmony_ci if (!release) 12788c2ecf20Sopenharmony_ci mutex_unlock(&bdev->bd_mutex); 12798c2ecf20Sopenharmony_ci if (err) 12808c2ecf20Sopenharmony_ci pr_warn("%s: partition scan of loop%d failed (rc=%d)\n", 12818c2ecf20Sopenharmony_ci __func__, lo_number, err); 12828c2ecf20Sopenharmony_ci /* Device is gone, no point in returning error */ 12838c2ecf20Sopenharmony_ci err = 0; 12848c2ecf20Sopenharmony_ci } 12858c2ecf20Sopenharmony_ci 12868c2ecf20Sopenharmony_ci /* 12878c2ecf20Sopenharmony_ci * lo->lo_state is set to Lo_unbound here after above partscan has 12888c2ecf20Sopenharmony_ci * finished. 12898c2ecf20Sopenharmony_ci * 12908c2ecf20Sopenharmony_ci * There cannot be anybody else entering __loop_clr_fd() as 12918c2ecf20Sopenharmony_ci * lo->lo_backing_file is already cleared and Lo_rundown state 12928c2ecf20Sopenharmony_ci * protects us from all the other places trying to change the 'lo' 12938c2ecf20Sopenharmony_ci * device. 12948c2ecf20Sopenharmony_ci */ 12958c2ecf20Sopenharmony_ci mutex_lock(&loop_ctl_mutex); 12968c2ecf20Sopenharmony_ci lo->lo_flags = 0; 12978c2ecf20Sopenharmony_ci if (!part_shift) 12988c2ecf20Sopenharmony_ci lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN; 12998c2ecf20Sopenharmony_ci lo->lo_state = Lo_unbound; 13008c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci /* 13038c2ecf20Sopenharmony_ci * Need not hold loop_ctl_mutex to fput backing file. 13048c2ecf20Sopenharmony_ci * Calling fput holding loop_ctl_mutex triggers a circular 13058c2ecf20Sopenharmony_ci * lock dependency possibility warning as fput can take 13068c2ecf20Sopenharmony_ci * bd_mutex which is usually taken before loop_ctl_mutex. 13078c2ecf20Sopenharmony_ci */ 13088c2ecf20Sopenharmony_ci if (filp) 13098c2ecf20Sopenharmony_ci fput(filp); 13108c2ecf20Sopenharmony_ci return err; 13118c2ecf20Sopenharmony_ci} 13128c2ecf20Sopenharmony_ci 13138c2ecf20Sopenharmony_cistatic int loop_clr_fd(struct loop_device *lo) 13148c2ecf20Sopenharmony_ci{ 13158c2ecf20Sopenharmony_ci int err; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci err = mutex_lock_killable(&loop_ctl_mutex); 13188c2ecf20Sopenharmony_ci if (err) 13198c2ecf20Sopenharmony_ci return err; 13208c2ecf20Sopenharmony_ci if (lo->lo_state != Lo_bound) { 13218c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 13228c2ecf20Sopenharmony_ci return -ENXIO; 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci /* 13258c2ecf20Sopenharmony_ci * If we've explicitly asked to tear down the loop device, 13268c2ecf20Sopenharmony_ci * and it has an elevated reference count, set it for auto-teardown when 13278c2ecf20Sopenharmony_ci * the last reference goes away. This stops $!~#$@ udev from 13288c2ecf20Sopenharmony_ci * preventing teardown because it decided that it needs to run blkid on 13298c2ecf20Sopenharmony_ci * the loopback device whenever they appear. xfstests is notorious for 13308c2ecf20Sopenharmony_ci * failing tests because blkid via udev races with a losetup 13318c2ecf20Sopenharmony_ci * <dev>/do something like mkfs/losetup -d <dev> causing the losetup -d 13328c2ecf20Sopenharmony_ci * command to fail with EBUSY. 13338c2ecf20Sopenharmony_ci */ 13348c2ecf20Sopenharmony_ci if (atomic_read(&lo->lo_refcnt) > 1) { 13358c2ecf20Sopenharmony_ci lo->lo_flags |= LO_FLAGS_AUTOCLEAR; 13368c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 13378c2ecf20Sopenharmony_ci return 0; 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci lo->lo_state = Lo_rundown; 13408c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci return __loop_clr_fd(lo, false); 13438c2ecf20Sopenharmony_ci} 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_cistatic int 13468c2ecf20Sopenharmony_ciloop_set_status(struct loop_device *lo, const struct loop_info64 *info) 13478c2ecf20Sopenharmony_ci{ 13488c2ecf20Sopenharmony_ci int err; 13498c2ecf20Sopenharmony_ci struct block_device *bdev; 13508c2ecf20Sopenharmony_ci kuid_t uid = current_uid(); 13518c2ecf20Sopenharmony_ci int prev_lo_flags; 13528c2ecf20Sopenharmony_ci bool partscan = false; 13538c2ecf20Sopenharmony_ci bool size_changed = false; 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci err = mutex_lock_killable(&loop_ctl_mutex); 13568c2ecf20Sopenharmony_ci if (err) 13578c2ecf20Sopenharmony_ci return err; 13588c2ecf20Sopenharmony_ci if (lo->lo_encrypt_key_size && 13598c2ecf20Sopenharmony_ci !uid_eq(lo->lo_key_owner, uid) && 13608c2ecf20Sopenharmony_ci !capable(CAP_SYS_ADMIN)) { 13618c2ecf20Sopenharmony_ci err = -EPERM; 13628c2ecf20Sopenharmony_ci goto out_unlock; 13638c2ecf20Sopenharmony_ci } 13648c2ecf20Sopenharmony_ci if (lo->lo_state != Lo_bound) { 13658c2ecf20Sopenharmony_ci err = -ENXIO; 13668c2ecf20Sopenharmony_ci goto out_unlock; 13678c2ecf20Sopenharmony_ci } 13688c2ecf20Sopenharmony_ci 13698c2ecf20Sopenharmony_ci if (lo->lo_offset != info->lo_offset || 13708c2ecf20Sopenharmony_ci lo->lo_sizelimit != info->lo_sizelimit) { 13718c2ecf20Sopenharmony_ci size_changed = true; 13728c2ecf20Sopenharmony_ci sync_blockdev(lo->lo_device); 13738c2ecf20Sopenharmony_ci invalidate_bdev(lo->lo_device); 13748c2ecf20Sopenharmony_ci } 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci /* I/O need to be drained during transfer transition */ 13778c2ecf20Sopenharmony_ci blk_mq_freeze_queue(lo->lo_queue); 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci if (size_changed && lo->lo_device->bd_inode->i_mapping->nrpages) { 13808c2ecf20Sopenharmony_ci /* If any pages were dirtied after invalidate_bdev(), try again */ 13818c2ecf20Sopenharmony_ci err = -EAGAIN; 13828c2ecf20Sopenharmony_ci pr_warn("%s: loop%d (%s) has still dirty pages (nrpages=%lu)\n", 13838c2ecf20Sopenharmony_ci __func__, lo->lo_number, lo->lo_file_name, 13848c2ecf20Sopenharmony_ci lo->lo_device->bd_inode->i_mapping->nrpages); 13858c2ecf20Sopenharmony_ci goto out_unfreeze; 13868c2ecf20Sopenharmony_ci } 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci prev_lo_flags = lo->lo_flags; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci err = loop_set_status_from_info(lo, info); 13918c2ecf20Sopenharmony_ci if (err) 13928c2ecf20Sopenharmony_ci goto out_unfreeze; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci /* Mask out flags that can't be set using LOOP_SET_STATUS. */ 13958c2ecf20Sopenharmony_ci lo->lo_flags &= LOOP_SET_STATUS_SETTABLE_FLAGS; 13968c2ecf20Sopenharmony_ci /* For those flags, use the previous values instead */ 13978c2ecf20Sopenharmony_ci lo->lo_flags |= prev_lo_flags & ~LOOP_SET_STATUS_SETTABLE_FLAGS; 13988c2ecf20Sopenharmony_ci /* For flags that can't be cleared, use previous values too */ 13998c2ecf20Sopenharmony_ci lo->lo_flags |= prev_lo_flags & ~LOOP_SET_STATUS_CLEARABLE_FLAGS; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci if (size_changed) { 14028c2ecf20Sopenharmony_ci loff_t new_size = get_size(lo->lo_offset, lo->lo_sizelimit, 14038c2ecf20Sopenharmony_ci lo->lo_backing_file); 14048c2ecf20Sopenharmony_ci loop_set_size(lo, new_size); 14058c2ecf20Sopenharmony_ci } 14068c2ecf20Sopenharmony_ci 14078c2ecf20Sopenharmony_ci loop_config_discard(lo); 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci /* update dio if lo_offset or transfer is changed */ 14108c2ecf20Sopenharmony_ci __loop_update_dio(lo, lo->use_dio); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ciout_unfreeze: 14138c2ecf20Sopenharmony_ci blk_mq_unfreeze_queue(lo->lo_queue); 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci if (!err && (lo->lo_flags & LO_FLAGS_PARTSCAN) && 14168c2ecf20Sopenharmony_ci !(prev_lo_flags & LO_FLAGS_PARTSCAN)) { 14178c2ecf20Sopenharmony_ci lo->lo_disk->flags &= ~GENHD_FL_NO_PART_SCAN; 14188c2ecf20Sopenharmony_ci bdev = lo->lo_device; 14198c2ecf20Sopenharmony_ci partscan = true; 14208c2ecf20Sopenharmony_ci } 14218c2ecf20Sopenharmony_ciout_unlock: 14228c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 14238c2ecf20Sopenharmony_ci if (partscan) 14248c2ecf20Sopenharmony_ci loop_reread_partitions(lo, bdev); 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci return err; 14278c2ecf20Sopenharmony_ci} 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_cistatic int 14308c2ecf20Sopenharmony_ciloop_get_status(struct loop_device *lo, struct loop_info64 *info) 14318c2ecf20Sopenharmony_ci{ 14328c2ecf20Sopenharmony_ci struct path path; 14338c2ecf20Sopenharmony_ci struct kstat stat; 14348c2ecf20Sopenharmony_ci int ret; 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci ret = mutex_lock_killable(&loop_ctl_mutex); 14378c2ecf20Sopenharmony_ci if (ret) 14388c2ecf20Sopenharmony_ci return ret; 14398c2ecf20Sopenharmony_ci if (lo->lo_state != Lo_bound) { 14408c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 14418c2ecf20Sopenharmony_ci return -ENXIO; 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci memset(info, 0, sizeof(*info)); 14458c2ecf20Sopenharmony_ci info->lo_number = lo->lo_number; 14468c2ecf20Sopenharmony_ci info->lo_offset = lo->lo_offset; 14478c2ecf20Sopenharmony_ci info->lo_sizelimit = lo->lo_sizelimit; 14488c2ecf20Sopenharmony_ci info->lo_flags = lo->lo_flags; 14498c2ecf20Sopenharmony_ci memcpy(info->lo_file_name, lo->lo_file_name, LO_NAME_SIZE); 14508c2ecf20Sopenharmony_ci memcpy(info->lo_crypt_name, lo->lo_crypt_name, LO_NAME_SIZE); 14518c2ecf20Sopenharmony_ci info->lo_encrypt_type = 14528c2ecf20Sopenharmony_ci lo->lo_encryption ? lo->lo_encryption->number : 0; 14538c2ecf20Sopenharmony_ci if (lo->lo_encrypt_key_size && capable(CAP_SYS_ADMIN)) { 14548c2ecf20Sopenharmony_ci info->lo_encrypt_key_size = lo->lo_encrypt_key_size; 14558c2ecf20Sopenharmony_ci memcpy(info->lo_encrypt_key, lo->lo_encrypt_key, 14568c2ecf20Sopenharmony_ci lo->lo_encrypt_key_size); 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci /* Drop loop_ctl_mutex while we call into the filesystem. */ 14608c2ecf20Sopenharmony_ci path = lo->lo_backing_file->f_path; 14618c2ecf20Sopenharmony_ci path_get(&path); 14628c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 14638c2ecf20Sopenharmony_ci ret = vfs_getattr(&path, &stat, STATX_INO, AT_STATX_SYNC_AS_STAT); 14648c2ecf20Sopenharmony_ci if (!ret) { 14658c2ecf20Sopenharmony_ci info->lo_device = huge_encode_dev(stat.dev); 14668c2ecf20Sopenharmony_ci info->lo_inode = stat.ino; 14678c2ecf20Sopenharmony_ci info->lo_rdevice = huge_encode_dev(stat.rdev); 14688c2ecf20Sopenharmony_ci } 14698c2ecf20Sopenharmony_ci path_put(&path); 14708c2ecf20Sopenharmony_ci return ret; 14718c2ecf20Sopenharmony_ci} 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_cistatic void 14748c2ecf20Sopenharmony_ciloop_info64_from_old(const struct loop_info *info, struct loop_info64 *info64) 14758c2ecf20Sopenharmony_ci{ 14768c2ecf20Sopenharmony_ci memset(info64, 0, sizeof(*info64)); 14778c2ecf20Sopenharmony_ci info64->lo_number = info->lo_number; 14788c2ecf20Sopenharmony_ci info64->lo_device = info->lo_device; 14798c2ecf20Sopenharmony_ci info64->lo_inode = info->lo_inode; 14808c2ecf20Sopenharmony_ci info64->lo_rdevice = info->lo_rdevice; 14818c2ecf20Sopenharmony_ci info64->lo_offset = info->lo_offset; 14828c2ecf20Sopenharmony_ci info64->lo_sizelimit = 0; 14838c2ecf20Sopenharmony_ci info64->lo_encrypt_type = info->lo_encrypt_type; 14848c2ecf20Sopenharmony_ci info64->lo_encrypt_key_size = info->lo_encrypt_key_size; 14858c2ecf20Sopenharmony_ci info64->lo_flags = info->lo_flags; 14868c2ecf20Sopenharmony_ci info64->lo_init[0] = info->lo_init[0]; 14878c2ecf20Sopenharmony_ci info64->lo_init[1] = info->lo_init[1]; 14888c2ecf20Sopenharmony_ci if (info->lo_encrypt_type == LO_CRYPT_CRYPTOAPI) 14898c2ecf20Sopenharmony_ci memcpy(info64->lo_crypt_name, info->lo_name, LO_NAME_SIZE); 14908c2ecf20Sopenharmony_ci else 14918c2ecf20Sopenharmony_ci memcpy(info64->lo_file_name, info->lo_name, LO_NAME_SIZE); 14928c2ecf20Sopenharmony_ci memcpy(info64->lo_encrypt_key, info->lo_encrypt_key, LO_KEY_SIZE); 14938c2ecf20Sopenharmony_ci} 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_cistatic int 14968c2ecf20Sopenharmony_ciloop_info64_to_old(const struct loop_info64 *info64, struct loop_info *info) 14978c2ecf20Sopenharmony_ci{ 14988c2ecf20Sopenharmony_ci memset(info, 0, sizeof(*info)); 14998c2ecf20Sopenharmony_ci info->lo_number = info64->lo_number; 15008c2ecf20Sopenharmony_ci info->lo_device = info64->lo_device; 15018c2ecf20Sopenharmony_ci info->lo_inode = info64->lo_inode; 15028c2ecf20Sopenharmony_ci info->lo_rdevice = info64->lo_rdevice; 15038c2ecf20Sopenharmony_ci info->lo_offset = info64->lo_offset; 15048c2ecf20Sopenharmony_ci info->lo_encrypt_type = info64->lo_encrypt_type; 15058c2ecf20Sopenharmony_ci info->lo_encrypt_key_size = info64->lo_encrypt_key_size; 15068c2ecf20Sopenharmony_ci info->lo_flags = info64->lo_flags; 15078c2ecf20Sopenharmony_ci info->lo_init[0] = info64->lo_init[0]; 15088c2ecf20Sopenharmony_ci info->lo_init[1] = info64->lo_init[1]; 15098c2ecf20Sopenharmony_ci if (info->lo_encrypt_type == LO_CRYPT_CRYPTOAPI) 15108c2ecf20Sopenharmony_ci memcpy(info->lo_name, info64->lo_crypt_name, LO_NAME_SIZE); 15118c2ecf20Sopenharmony_ci else 15128c2ecf20Sopenharmony_ci memcpy(info->lo_name, info64->lo_file_name, LO_NAME_SIZE); 15138c2ecf20Sopenharmony_ci memcpy(info->lo_encrypt_key, info64->lo_encrypt_key, LO_KEY_SIZE); 15148c2ecf20Sopenharmony_ci 15158c2ecf20Sopenharmony_ci /* error in case values were truncated */ 15168c2ecf20Sopenharmony_ci if (info->lo_device != info64->lo_device || 15178c2ecf20Sopenharmony_ci info->lo_rdevice != info64->lo_rdevice || 15188c2ecf20Sopenharmony_ci info->lo_inode != info64->lo_inode || 15198c2ecf20Sopenharmony_ci info->lo_offset != info64->lo_offset) 15208c2ecf20Sopenharmony_ci return -EOVERFLOW; 15218c2ecf20Sopenharmony_ci 15228c2ecf20Sopenharmony_ci return 0; 15238c2ecf20Sopenharmony_ci} 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_cistatic int 15268c2ecf20Sopenharmony_ciloop_set_status_old(struct loop_device *lo, const struct loop_info __user *arg) 15278c2ecf20Sopenharmony_ci{ 15288c2ecf20Sopenharmony_ci struct loop_info info; 15298c2ecf20Sopenharmony_ci struct loop_info64 info64; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci if (copy_from_user(&info, arg, sizeof (struct loop_info))) 15328c2ecf20Sopenharmony_ci return -EFAULT; 15338c2ecf20Sopenharmony_ci loop_info64_from_old(&info, &info64); 15348c2ecf20Sopenharmony_ci return loop_set_status(lo, &info64); 15358c2ecf20Sopenharmony_ci} 15368c2ecf20Sopenharmony_ci 15378c2ecf20Sopenharmony_cistatic int 15388c2ecf20Sopenharmony_ciloop_set_status64(struct loop_device *lo, const struct loop_info64 __user *arg) 15398c2ecf20Sopenharmony_ci{ 15408c2ecf20Sopenharmony_ci struct loop_info64 info64; 15418c2ecf20Sopenharmony_ci 15428c2ecf20Sopenharmony_ci if (copy_from_user(&info64, arg, sizeof (struct loop_info64))) 15438c2ecf20Sopenharmony_ci return -EFAULT; 15448c2ecf20Sopenharmony_ci return loop_set_status(lo, &info64); 15458c2ecf20Sopenharmony_ci} 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_cistatic int 15488c2ecf20Sopenharmony_ciloop_get_status_old(struct loop_device *lo, struct loop_info __user *arg) { 15498c2ecf20Sopenharmony_ci struct loop_info info; 15508c2ecf20Sopenharmony_ci struct loop_info64 info64; 15518c2ecf20Sopenharmony_ci int err; 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci if (!arg) 15548c2ecf20Sopenharmony_ci return -EINVAL; 15558c2ecf20Sopenharmony_ci err = loop_get_status(lo, &info64); 15568c2ecf20Sopenharmony_ci if (!err) 15578c2ecf20Sopenharmony_ci err = loop_info64_to_old(&info64, &info); 15588c2ecf20Sopenharmony_ci if (!err && copy_to_user(arg, &info, sizeof(info))) 15598c2ecf20Sopenharmony_ci err = -EFAULT; 15608c2ecf20Sopenharmony_ci 15618c2ecf20Sopenharmony_ci return err; 15628c2ecf20Sopenharmony_ci} 15638c2ecf20Sopenharmony_ci 15648c2ecf20Sopenharmony_cistatic int 15658c2ecf20Sopenharmony_ciloop_get_status64(struct loop_device *lo, struct loop_info64 __user *arg) { 15668c2ecf20Sopenharmony_ci struct loop_info64 info64; 15678c2ecf20Sopenharmony_ci int err; 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci if (!arg) 15708c2ecf20Sopenharmony_ci return -EINVAL; 15718c2ecf20Sopenharmony_ci err = loop_get_status(lo, &info64); 15728c2ecf20Sopenharmony_ci if (!err && copy_to_user(arg, &info64, sizeof(info64))) 15738c2ecf20Sopenharmony_ci err = -EFAULT; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci return err; 15768c2ecf20Sopenharmony_ci} 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_cistatic int loop_set_capacity(struct loop_device *lo) 15798c2ecf20Sopenharmony_ci{ 15808c2ecf20Sopenharmony_ci loff_t size; 15818c2ecf20Sopenharmony_ci 15828c2ecf20Sopenharmony_ci if (unlikely(lo->lo_state != Lo_bound)) 15838c2ecf20Sopenharmony_ci return -ENXIO; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci size = get_loop_size(lo, lo->lo_backing_file); 15868c2ecf20Sopenharmony_ci loop_set_size(lo, size); 15878c2ecf20Sopenharmony_ci 15888c2ecf20Sopenharmony_ci return 0; 15898c2ecf20Sopenharmony_ci} 15908c2ecf20Sopenharmony_ci 15918c2ecf20Sopenharmony_cistatic int loop_set_dio(struct loop_device *lo, unsigned long arg) 15928c2ecf20Sopenharmony_ci{ 15938c2ecf20Sopenharmony_ci int error = -ENXIO; 15948c2ecf20Sopenharmony_ci if (lo->lo_state != Lo_bound) 15958c2ecf20Sopenharmony_ci goto out; 15968c2ecf20Sopenharmony_ci 15978c2ecf20Sopenharmony_ci __loop_update_dio(lo, !!arg); 15988c2ecf20Sopenharmony_ci if (lo->use_dio == !!arg) 15998c2ecf20Sopenharmony_ci return 0; 16008c2ecf20Sopenharmony_ci error = -EINVAL; 16018c2ecf20Sopenharmony_ci out: 16028c2ecf20Sopenharmony_ci return error; 16038c2ecf20Sopenharmony_ci} 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_cistatic int loop_set_block_size(struct loop_device *lo, unsigned long arg) 16068c2ecf20Sopenharmony_ci{ 16078c2ecf20Sopenharmony_ci int err = 0; 16088c2ecf20Sopenharmony_ci 16098c2ecf20Sopenharmony_ci if (lo->lo_state != Lo_bound) 16108c2ecf20Sopenharmony_ci return -ENXIO; 16118c2ecf20Sopenharmony_ci 16128c2ecf20Sopenharmony_ci err = blk_validate_block_size(arg); 16138c2ecf20Sopenharmony_ci if (err) 16148c2ecf20Sopenharmony_ci return err; 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci if (lo->lo_queue->limits.logical_block_size == arg) 16178c2ecf20Sopenharmony_ci return 0; 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ci sync_blockdev(lo->lo_device); 16208c2ecf20Sopenharmony_ci invalidate_bdev(lo->lo_device); 16218c2ecf20Sopenharmony_ci 16228c2ecf20Sopenharmony_ci blk_mq_freeze_queue(lo->lo_queue); 16238c2ecf20Sopenharmony_ci 16248c2ecf20Sopenharmony_ci /* invalidate_bdev should have truncated all the pages */ 16258c2ecf20Sopenharmony_ci if (lo->lo_device->bd_inode->i_mapping->nrpages) { 16268c2ecf20Sopenharmony_ci err = -EAGAIN; 16278c2ecf20Sopenharmony_ci pr_warn("%s: loop%d (%s) has still dirty pages (nrpages=%lu)\n", 16288c2ecf20Sopenharmony_ci __func__, lo->lo_number, lo->lo_file_name, 16298c2ecf20Sopenharmony_ci lo->lo_device->bd_inode->i_mapping->nrpages); 16308c2ecf20Sopenharmony_ci goto out_unfreeze; 16318c2ecf20Sopenharmony_ci } 16328c2ecf20Sopenharmony_ci 16338c2ecf20Sopenharmony_ci blk_queue_logical_block_size(lo->lo_queue, arg); 16348c2ecf20Sopenharmony_ci blk_queue_physical_block_size(lo->lo_queue, arg); 16358c2ecf20Sopenharmony_ci blk_queue_io_min(lo->lo_queue, arg); 16368c2ecf20Sopenharmony_ci loop_update_dio(lo); 16378c2ecf20Sopenharmony_ciout_unfreeze: 16388c2ecf20Sopenharmony_ci blk_mq_unfreeze_queue(lo->lo_queue); 16398c2ecf20Sopenharmony_ci 16408c2ecf20Sopenharmony_ci return err; 16418c2ecf20Sopenharmony_ci} 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_cistatic int lo_simple_ioctl(struct loop_device *lo, unsigned int cmd, 16448c2ecf20Sopenharmony_ci unsigned long arg) 16458c2ecf20Sopenharmony_ci{ 16468c2ecf20Sopenharmony_ci int err; 16478c2ecf20Sopenharmony_ci 16488c2ecf20Sopenharmony_ci err = mutex_lock_killable(&loop_ctl_mutex); 16498c2ecf20Sopenharmony_ci if (err) 16508c2ecf20Sopenharmony_ci return err; 16518c2ecf20Sopenharmony_ci switch (cmd) { 16528c2ecf20Sopenharmony_ci case LOOP_SET_CAPACITY: 16538c2ecf20Sopenharmony_ci err = loop_set_capacity(lo); 16548c2ecf20Sopenharmony_ci break; 16558c2ecf20Sopenharmony_ci case LOOP_SET_DIRECT_IO: 16568c2ecf20Sopenharmony_ci err = loop_set_dio(lo, arg); 16578c2ecf20Sopenharmony_ci break; 16588c2ecf20Sopenharmony_ci case LOOP_SET_BLOCK_SIZE: 16598c2ecf20Sopenharmony_ci err = loop_set_block_size(lo, arg); 16608c2ecf20Sopenharmony_ci break; 16618c2ecf20Sopenharmony_ci default: 16628c2ecf20Sopenharmony_ci err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL; 16638c2ecf20Sopenharmony_ci } 16648c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 16658c2ecf20Sopenharmony_ci return err; 16668c2ecf20Sopenharmony_ci} 16678c2ecf20Sopenharmony_ci 16688c2ecf20Sopenharmony_cistatic int lo_ioctl(struct block_device *bdev, fmode_t mode, 16698c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 16708c2ecf20Sopenharmony_ci{ 16718c2ecf20Sopenharmony_ci struct loop_device *lo = bdev->bd_disk->private_data; 16728c2ecf20Sopenharmony_ci void __user *argp = (void __user *) arg; 16738c2ecf20Sopenharmony_ci int err; 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci switch (cmd) { 16768c2ecf20Sopenharmony_ci case LOOP_SET_FD: { 16778c2ecf20Sopenharmony_ci /* 16788c2ecf20Sopenharmony_ci * Legacy case - pass in a zeroed out struct loop_config with 16798c2ecf20Sopenharmony_ci * only the file descriptor set , which corresponds with the 16808c2ecf20Sopenharmony_ci * default parameters we'd have used otherwise. 16818c2ecf20Sopenharmony_ci */ 16828c2ecf20Sopenharmony_ci struct loop_config config; 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci memset(&config, 0, sizeof(config)); 16858c2ecf20Sopenharmony_ci config.fd = arg; 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_ci return loop_configure(lo, mode, bdev, &config); 16888c2ecf20Sopenharmony_ci } 16898c2ecf20Sopenharmony_ci case LOOP_CONFIGURE: { 16908c2ecf20Sopenharmony_ci struct loop_config config; 16918c2ecf20Sopenharmony_ci 16928c2ecf20Sopenharmony_ci if (copy_from_user(&config, argp, sizeof(config))) 16938c2ecf20Sopenharmony_ci return -EFAULT; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci return loop_configure(lo, mode, bdev, &config); 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci case LOOP_CHANGE_FD: 16988c2ecf20Sopenharmony_ci return loop_change_fd(lo, bdev, arg); 16998c2ecf20Sopenharmony_ci case LOOP_CLR_FD: 17008c2ecf20Sopenharmony_ci return loop_clr_fd(lo); 17018c2ecf20Sopenharmony_ci case LOOP_SET_STATUS: 17028c2ecf20Sopenharmony_ci err = -EPERM; 17038c2ecf20Sopenharmony_ci if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) { 17048c2ecf20Sopenharmony_ci err = loop_set_status_old(lo, argp); 17058c2ecf20Sopenharmony_ci } 17068c2ecf20Sopenharmony_ci break; 17078c2ecf20Sopenharmony_ci case LOOP_GET_STATUS: 17088c2ecf20Sopenharmony_ci return loop_get_status_old(lo, argp); 17098c2ecf20Sopenharmony_ci case LOOP_SET_STATUS64: 17108c2ecf20Sopenharmony_ci err = -EPERM; 17118c2ecf20Sopenharmony_ci if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) { 17128c2ecf20Sopenharmony_ci err = loop_set_status64(lo, argp); 17138c2ecf20Sopenharmony_ci } 17148c2ecf20Sopenharmony_ci break; 17158c2ecf20Sopenharmony_ci case LOOP_GET_STATUS64: 17168c2ecf20Sopenharmony_ci return loop_get_status64(lo, argp); 17178c2ecf20Sopenharmony_ci case LOOP_SET_CAPACITY: 17188c2ecf20Sopenharmony_ci case LOOP_SET_DIRECT_IO: 17198c2ecf20Sopenharmony_ci case LOOP_SET_BLOCK_SIZE: 17208c2ecf20Sopenharmony_ci if (!(mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN)) 17218c2ecf20Sopenharmony_ci return -EPERM; 17228c2ecf20Sopenharmony_ci fallthrough; 17238c2ecf20Sopenharmony_ci default: 17248c2ecf20Sopenharmony_ci err = lo_simple_ioctl(lo, cmd, arg); 17258c2ecf20Sopenharmony_ci break; 17268c2ecf20Sopenharmony_ci } 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci return err; 17298c2ecf20Sopenharmony_ci} 17308c2ecf20Sopenharmony_ci 17318c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 17328c2ecf20Sopenharmony_cistruct compat_loop_info { 17338c2ecf20Sopenharmony_ci compat_int_t lo_number; /* ioctl r/o */ 17348c2ecf20Sopenharmony_ci compat_dev_t lo_device; /* ioctl r/o */ 17358c2ecf20Sopenharmony_ci compat_ulong_t lo_inode; /* ioctl r/o */ 17368c2ecf20Sopenharmony_ci compat_dev_t lo_rdevice; /* ioctl r/o */ 17378c2ecf20Sopenharmony_ci compat_int_t lo_offset; 17388c2ecf20Sopenharmony_ci compat_int_t lo_encrypt_type; 17398c2ecf20Sopenharmony_ci compat_int_t lo_encrypt_key_size; /* ioctl w/o */ 17408c2ecf20Sopenharmony_ci compat_int_t lo_flags; /* ioctl r/o */ 17418c2ecf20Sopenharmony_ci char lo_name[LO_NAME_SIZE]; 17428c2ecf20Sopenharmony_ci unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ 17438c2ecf20Sopenharmony_ci compat_ulong_t lo_init[2]; 17448c2ecf20Sopenharmony_ci char reserved[4]; 17458c2ecf20Sopenharmony_ci}; 17468c2ecf20Sopenharmony_ci 17478c2ecf20Sopenharmony_ci/* 17488c2ecf20Sopenharmony_ci * Transfer 32-bit compatibility structure in userspace to 64-bit loop info 17498c2ecf20Sopenharmony_ci * - noinlined to reduce stack space usage in main part of driver 17508c2ecf20Sopenharmony_ci */ 17518c2ecf20Sopenharmony_cistatic noinline int 17528c2ecf20Sopenharmony_ciloop_info64_from_compat(const struct compat_loop_info __user *arg, 17538c2ecf20Sopenharmony_ci struct loop_info64 *info64) 17548c2ecf20Sopenharmony_ci{ 17558c2ecf20Sopenharmony_ci struct compat_loop_info info; 17568c2ecf20Sopenharmony_ci 17578c2ecf20Sopenharmony_ci if (copy_from_user(&info, arg, sizeof(info))) 17588c2ecf20Sopenharmony_ci return -EFAULT; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci memset(info64, 0, sizeof(*info64)); 17618c2ecf20Sopenharmony_ci info64->lo_number = info.lo_number; 17628c2ecf20Sopenharmony_ci info64->lo_device = info.lo_device; 17638c2ecf20Sopenharmony_ci info64->lo_inode = info.lo_inode; 17648c2ecf20Sopenharmony_ci info64->lo_rdevice = info.lo_rdevice; 17658c2ecf20Sopenharmony_ci info64->lo_offset = info.lo_offset; 17668c2ecf20Sopenharmony_ci info64->lo_sizelimit = 0; 17678c2ecf20Sopenharmony_ci info64->lo_encrypt_type = info.lo_encrypt_type; 17688c2ecf20Sopenharmony_ci info64->lo_encrypt_key_size = info.lo_encrypt_key_size; 17698c2ecf20Sopenharmony_ci info64->lo_flags = info.lo_flags; 17708c2ecf20Sopenharmony_ci info64->lo_init[0] = info.lo_init[0]; 17718c2ecf20Sopenharmony_ci info64->lo_init[1] = info.lo_init[1]; 17728c2ecf20Sopenharmony_ci if (info.lo_encrypt_type == LO_CRYPT_CRYPTOAPI) 17738c2ecf20Sopenharmony_ci memcpy(info64->lo_crypt_name, info.lo_name, LO_NAME_SIZE); 17748c2ecf20Sopenharmony_ci else 17758c2ecf20Sopenharmony_ci memcpy(info64->lo_file_name, info.lo_name, LO_NAME_SIZE); 17768c2ecf20Sopenharmony_ci memcpy(info64->lo_encrypt_key, info.lo_encrypt_key, LO_KEY_SIZE); 17778c2ecf20Sopenharmony_ci return 0; 17788c2ecf20Sopenharmony_ci} 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci/* 17818c2ecf20Sopenharmony_ci * Transfer 64-bit loop info to 32-bit compatibility structure in userspace 17828c2ecf20Sopenharmony_ci * - noinlined to reduce stack space usage in main part of driver 17838c2ecf20Sopenharmony_ci */ 17848c2ecf20Sopenharmony_cistatic noinline int 17858c2ecf20Sopenharmony_ciloop_info64_to_compat(const struct loop_info64 *info64, 17868c2ecf20Sopenharmony_ci struct compat_loop_info __user *arg) 17878c2ecf20Sopenharmony_ci{ 17888c2ecf20Sopenharmony_ci struct compat_loop_info info; 17898c2ecf20Sopenharmony_ci 17908c2ecf20Sopenharmony_ci memset(&info, 0, sizeof(info)); 17918c2ecf20Sopenharmony_ci info.lo_number = info64->lo_number; 17928c2ecf20Sopenharmony_ci info.lo_device = info64->lo_device; 17938c2ecf20Sopenharmony_ci info.lo_inode = info64->lo_inode; 17948c2ecf20Sopenharmony_ci info.lo_rdevice = info64->lo_rdevice; 17958c2ecf20Sopenharmony_ci info.lo_offset = info64->lo_offset; 17968c2ecf20Sopenharmony_ci info.lo_encrypt_type = info64->lo_encrypt_type; 17978c2ecf20Sopenharmony_ci info.lo_encrypt_key_size = info64->lo_encrypt_key_size; 17988c2ecf20Sopenharmony_ci info.lo_flags = info64->lo_flags; 17998c2ecf20Sopenharmony_ci info.lo_init[0] = info64->lo_init[0]; 18008c2ecf20Sopenharmony_ci info.lo_init[1] = info64->lo_init[1]; 18018c2ecf20Sopenharmony_ci if (info.lo_encrypt_type == LO_CRYPT_CRYPTOAPI) 18028c2ecf20Sopenharmony_ci memcpy(info.lo_name, info64->lo_crypt_name, LO_NAME_SIZE); 18038c2ecf20Sopenharmony_ci else 18048c2ecf20Sopenharmony_ci memcpy(info.lo_name, info64->lo_file_name, LO_NAME_SIZE); 18058c2ecf20Sopenharmony_ci memcpy(info.lo_encrypt_key, info64->lo_encrypt_key, LO_KEY_SIZE); 18068c2ecf20Sopenharmony_ci 18078c2ecf20Sopenharmony_ci /* error in case values were truncated */ 18088c2ecf20Sopenharmony_ci if (info.lo_device != info64->lo_device || 18098c2ecf20Sopenharmony_ci info.lo_rdevice != info64->lo_rdevice || 18108c2ecf20Sopenharmony_ci info.lo_inode != info64->lo_inode || 18118c2ecf20Sopenharmony_ci info.lo_offset != info64->lo_offset || 18128c2ecf20Sopenharmony_ci info.lo_init[0] != info64->lo_init[0] || 18138c2ecf20Sopenharmony_ci info.lo_init[1] != info64->lo_init[1]) 18148c2ecf20Sopenharmony_ci return -EOVERFLOW; 18158c2ecf20Sopenharmony_ci 18168c2ecf20Sopenharmony_ci if (copy_to_user(arg, &info, sizeof(info))) 18178c2ecf20Sopenharmony_ci return -EFAULT; 18188c2ecf20Sopenharmony_ci return 0; 18198c2ecf20Sopenharmony_ci} 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_cistatic int 18228c2ecf20Sopenharmony_ciloop_set_status_compat(struct loop_device *lo, 18238c2ecf20Sopenharmony_ci const struct compat_loop_info __user *arg) 18248c2ecf20Sopenharmony_ci{ 18258c2ecf20Sopenharmony_ci struct loop_info64 info64; 18268c2ecf20Sopenharmony_ci int ret; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci ret = loop_info64_from_compat(arg, &info64); 18298c2ecf20Sopenharmony_ci if (ret < 0) 18308c2ecf20Sopenharmony_ci return ret; 18318c2ecf20Sopenharmony_ci return loop_set_status(lo, &info64); 18328c2ecf20Sopenharmony_ci} 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_cistatic int 18358c2ecf20Sopenharmony_ciloop_get_status_compat(struct loop_device *lo, 18368c2ecf20Sopenharmony_ci struct compat_loop_info __user *arg) 18378c2ecf20Sopenharmony_ci{ 18388c2ecf20Sopenharmony_ci struct loop_info64 info64; 18398c2ecf20Sopenharmony_ci int err; 18408c2ecf20Sopenharmony_ci 18418c2ecf20Sopenharmony_ci if (!arg) 18428c2ecf20Sopenharmony_ci return -EINVAL; 18438c2ecf20Sopenharmony_ci err = loop_get_status(lo, &info64); 18448c2ecf20Sopenharmony_ci if (!err) 18458c2ecf20Sopenharmony_ci err = loop_info64_to_compat(&info64, arg); 18468c2ecf20Sopenharmony_ci return err; 18478c2ecf20Sopenharmony_ci} 18488c2ecf20Sopenharmony_ci 18498c2ecf20Sopenharmony_cistatic int lo_compat_ioctl(struct block_device *bdev, fmode_t mode, 18508c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 18518c2ecf20Sopenharmony_ci{ 18528c2ecf20Sopenharmony_ci struct loop_device *lo = bdev->bd_disk->private_data; 18538c2ecf20Sopenharmony_ci int err; 18548c2ecf20Sopenharmony_ci 18558c2ecf20Sopenharmony_ci switch(cmd) { 18568c2ecf20Sopenharmony_ci case LOOP_SET_STATUS: 18578c2ecf20Sopenharmony_ci err = loop_set_status_compat(lo, 18588c2ecf20Sopenharmony_ci (const struct compat_loop_info __user *)arg); 18598c2ecf20Sopenharmony_ci break; 18608c2ecf20Sopenharmony_ci case LOOP_GET_STATUS: 18618c2ecf20Sopenharmony_ci err = loop_get_status_compat(lo, 18628c2ecf20Sopenharmony_ci (struct compat_loop_info __user *)arg); 18638c2ecf20Sopenharmony_ci break; 18648c2ecf20Sopenharmony_ci case LOOP_SET_CAPACITY: 18658c2ecf20Sopenharmony_ci case LOOP_CLR_FD: 18668c2ecf20Sopenharmony_ci case LOOP_GET_STATUS64: 18678c2ecf20Sopenharmony_ci case LOOP_SET_STATUS64: 18688c2ecf20Sopenharmony_ci case LOOP_CONFIGURE: 18698c2ecf20Sopenharmony_ci arg = (unsigned long) compat_ptr(arg); 18708c2ecf20Sopenharmony_ci fallthrough; 18718c2ecf20Sopenharmony_ci case LOOP_SET_FD: 18728c2ecf20Sopenharmony_ci case LOOP_CHANGE_FD: 18738c2ecf20Sopenharmony_ci case LOOP_SET_BLOCK_SIZE: 18748c2ecf20Sopenharmony_ci case LOOP_SET_DIRECT_IO: 18758c2ecf20Sopenharmony_ci err = lo_ioctl(bdev, mode, cmd, arg); 18768c2ecf20Sopenharmony_ci break; 18778c2ecf20Sopenharmony_ci default: 18788c2ecf20Sopenharmony_ci err = -ENOIOCTLCMD; 18798c2ecf20Sopenharmony_ci break; 18808c2ecf20Sopenharmony_ci } 18818c2ecf20Sopenharmony_ci return err; 18828c2ecf20Sopenharmony_ci} 18838c2ecf20Sopenharmony_ci#endif 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_cistatic int lo_open(struct block_device *bdev, fmode_t mode) 18868c2ecf20Sopenharmony_ci{ 18878c2ecf20Sopenharmony_ci struct loop_device *lo; 18888c2ecf20Sopenharmony_ci int err; 18898c2ecf20Sopenharmony_ci 18908c2ecf20Sopenharmony_ci err = mutex_lock_killable(&loop_ctl_mutex); 18918c2ecf20Sopenharmony_ci if (err) 18928c2ecf20Sopenharmony_ci return err; 18938c2ecf20Sopenharmony_ci lo = bdev->bd_disk->private_data; 18948c2ecf20Sopenharmony_ci if (!lo) { 18958c2ecf20Sopenharmony_ci err = -ENXIO; 18968c2ecf20Sopenharmony_ci goto out; 18978c2ecf20Sopenharmony_ci } 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci atomic_inc(&lo->lo_refcnt); 19008c2ecf20Sopenharmony_ciout: 19018c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 19028c2ecf20Sopenharmony_ci return err; 19038c2ecf20Sopenharmony_ci} 19048c2ecf20Sopenharmony_ci 19058c2ecf20Sopenharmony_cistatic void lo_release(struct gendisk *disk, fmode_t mode) 19068c2ecf20Sopenharmony_ci{ 19078c2ecf20Sopenharmony_ci struct loop_device *lo; 19088c2ecf20Sopenharmony_ci 19098c2ecf20Sopenharmony_ci mutex_lock(&loop_ctl_mutex); 19108c2ecf20Sopenharmony_ci lo = disk->private_data; 19118c2ecf20Sopenharmony_ci if (atomic_dec_return(&lo->lo_refcnt)) 19128c2ecf20Sopenharmony_ci goto out_unlock; 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_ci if (lo->lo_flags & LO_FLAGS_AUTOCLEAR) { 19158c2ecf20Sopenharmony_ci if (lo->lo_state != Lo_bound) 19168c2ecf20Sopenharmony_ci goto out_unlock; 19178c2ecf20Sopenharmony_ci lo->lo_state = Lo_rundown; 19188c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 19198c2ecf20Sopenharmony_ci /* 19208c2ecf20Sopenharmony_ci * In autoclear mode, stop the loop thread 19218c2ecf20Sopenharmony_ci * and remove configuration after last close. 19228c2ecf20Sopenharmony_ci */ 19238c2ecf20Sopenharmony_ci __loop_clr_fd(lo, true); 19248c2ecf20Sopenharmony_ci return; 19258c2ecf20Sopenharmony_ci } else if (lo->lo_state == Lo_bound) { 19268c2ecf20Sopenharmony_ci /* 19278c2ecf20Sopenharmony_ci * Otherwise keep thread (if running) and config, 19288c2ecf20Sopenharmony_ci * but flush possible ongoing bios in thread. 19298c2ecf20Sopenharmony_ci */ 19308c2ecf20Sopenharmony_ci blk_mq_freeze_queue(lo->lo_queue); 19318c2ecf20Sopenharmony_ci blk_mq_unfreeze_queue(lo->lo_queue); 19328c2ecf20Sopenharmony_ci } 19338c2ecf20Sopenharmony_ci 19348c2ecf20Sopenharmony_ciout_unlock: 19358c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 19368c2ecf20Sopenharmony_ci} 19378c2ecf20Sopenharmony_ci 19388c2ecf20Sopenharmony_cistatic const struct block_device_operations lo_fops = { 19398c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 19408c2ecf20Sopenharmony_ci .open = lo_open, 19418c2ecf20Sopenharmony_ci .release = lo_release, 19428c2ecf20Sopenharmony_ci .ioctl = lo_ioctl, 19438c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT 19448c2ecf20Sopenharmony_ci .compat_ioctl = lo_compat_ioctl, 19458c2ecf20Sopenharmony_ci#endif 19468c2ecf20Sopenharmony_ci}; 19478c2ecf20Sopenharmony_ci 19488c2ecf20Sopenharmony_ci/* 19498c2ecf20Sopenharmony_ci * And now the modules code and kernel interface. 19508c2ecf20Sopenharmony_ci */ 19518c2ecf20Sopenharmony_cistatic int max_loop; 19528c2ecf20Sopenharmony_cimodule_param(max_loop, int, 0444); 19538c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_loop, "Maximum number of loop devices"); 19548c2ecf20Sopenharmony_cimodule_param(max_part, int, 0444); 19558c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_part, "Maximum number of partitions per loop device"); 19568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 19578c2ecf20Sopenharmony_ciMODULE_ALIAS_BLOCKDEV_MAJOR(LOOP_MAJOR); 19588c2ecf20Sopenharmony_ci 19598c2ecf20Sopenharmony_ciint loop_register_transfer(struct loop_func_table *funcs) 19608c2ecf20Sopenharmony_ci{ 19618c2ecf20Sopenharmony_ci unsigned int n = funcs->number; 19628c2ecf20Sopenharmony_ci 19638c2ecf20Sopenharmony_ci if (n >= MAX_LO_CRYPT || xfer_funcs[n]) 19648c2ecf20Sopenharmony_ci return -EINVAL; 19658c2ecf20Sopenharmony_ci xfer_funcs[n] = funcs; 19668c2ecf20Sopenharmony_ci return 0; 19678c2ecf20Sopenharmony_ci} 19688c2ecf20Sopenharmony_ci 19698c2ecf20Sopenharmony_cistatic int unregister_transfer_cb(int id, void *ptr, void *data) 19708c2ecf20Sopenharmony_ci{ 19718c2ecf20Sopenharmony_ci struct loop_device *lo = ptr; 19728c2ecf20Sopenharmony_ci struct loop_func_table *xfer = data; 19738c2ecf20Sopenharmony_ci 19748c2ecf20Sopenharmony_ci mutex_lock(&loop_ctl_mutex); 19758c2ecf20Sopenharmony_ci if (lo->lo_encryption == xfer) 19768c2ecf20Sopenharmony_ci loop_release_xfer(lo); 19778c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 19788c2ecf20Sopenharmony_ci return 0; 19798c2ecf20Sopenharmony_ci} 19808c2ecf20Sopenharmony_ci 19818c2ecf20Sopenharmony_ciint loop_unregister_transfer(int number) 19828c2ecf20Sopenharmony_ci{ 19838c2ecf20Sopenharmony_ci unsigned int n = number; 19848c2ecf20Sopenharmony_ci struct loop_func_table *xfer; 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci if (n == 0 || n >= MAX_LO_CRYPT || (xfer = xfer_funcs[n]) == NULL) 19878c2ecf20Sopenharmony_ci return -EINVAL; 19888c2ecf20Sopenharmony_ci 19898c2ecf20Sopenharmony_ci xfer_funcs[n] = NULL; 19908c2ecf20Sopenharmony_ci idr_for_each(&loop_index_idr, &unregister_transfer_cb, xfer); 19918c2ecf20Sopenharmony_ci return 0; 19928c2ecf20Sopenharmony_ci} 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ciEXPORT_SYMBOL(loop_register_transfer); 19958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(loop_unregister_transfer); 19968c2ecf20Sopenharmony_ci 19978c2ecf20Sopenharmony_cistatic blk_status_t loop_queue_rq(struct blk_mq_hw_ctx *hctx, 19988c2ecf20Sopenharmony_ci const struct blk_mq_queue_data *bd) 19998c2ecf20Sopenharmony_ci{ 20008c2ecf20Sopenharmony_ci struct request *rq = bd->rq; 20018c2ecf20Sopenharmony_ci struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq); 20028c2ecf20Sopenharmony_ci struct loop_device *lo = rq->q->queuedata; 20038c2ecf20Sopenharmony_ci 20048c2ecf20Sopenharmony_ci blk_mq_start_request(rq); 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci if (lo->lo_state != Lo_bound) 20078c2ecf20Sopenharmony_ci return BLK_STS_IOERR; 20088c2ecf20Sopenharmony_ci 20098c2ecf20Sopenharmony_ci switch (req_op(rq)) { 20108c2ecf20Sopenharmony_ci case REQ_OP_FLUSH: 20118c2ecf20Sopenharmony_ci case REQ_OP_DISCARD: 20128c2ecf20Sopenharmony_ci case REQ_OP_WRITE_ZEROES: 20138c2ecf20Sopenharmony_ci cmd->use_aio = false; 20148c2ecf20Sopenharmony_ci break; 20158c2ecf20Sopenharmony_ci default: 20168c2ecf20Sopenharmony_ci cmd->use_aio = lo->use_dio; 20178c2ecf20Sopenharmony_ci break; 20188c2ecf20Sopenharmony_ci } 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci /* always use the first bio's css */ 20218c2ecf20Sopenharmony_ci#ifdef CONFIG_BLK_CGROUP 20228c2ecf20Sopenharmony_ci if (cmd->use_aio && rq->bio && rq->bio->bi_blkg) { 20238c2ecf20Sopenharmony_ci cmd->css = &bio_blkcg(rq->bio)->css; 20248c2ecf20Sopenharmony_ci css_get(cmd->css); 20258c2ecf20Sopenharmony_ci } else 20268c2ecf20Sopenharmony_ci#endif 20278c2ecf20Sopenharmony_ci cmd->css = NULL; 20288c2ecf20Sopenharmony_ci kthread_queue_work(&lo->worker, &cmd->work); 20298c2ecf20Sopenharmony_ci 20308c2ecf20Sopenharmony_ci return BLK_STS_OK; 20318c2ecf20Sopenharmony_ci} 20328c2ecf20Sopenharmony_ci 20338c2ecf20Sopenharmony_cistatic void loop_handle_cmd(struct loop_cmd *cmd) 20348c2ecf20Sopenharmony_ci{ 20358c2ecf20Sopenharmony_ci struct request *rq = blk_mq_rq_from_pdu(cmd); 20368c2ecf20Sopenharmony_ci const bool write = op_is_write(req_op(rq)); 20378c2ecf20Sopenharmony_ci struct loop_device *lo = rq->q->queuedata; 20388c2ecf20Sopenharmony_ci int ret = 0; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci if (write && (lo->lo_flags & LO_FLAGS_READ_ONLY)) { 20418c2ecf20Sopenharmony_ci ret = -EIO; 20428c2ecf20Sopenharmony_ci goto failed; 20438c2ecf20Sopenharmony_ci } 20448c2ecf20Sopenharmony_ci 20458c2ecf20Sopenharmony_ci ret = do_req_filebacked(lo, rq); 20468c2ecf20Sopenharmony_ci failed: 20478c2ecf20Sopenharmony_ci /* complete non-aio request */ 20488c2ecf20Sopenharmony_ci if (!cmd->use_aio || ret) { 20498c2ecf20Sopenharmony_ci if (ret == -EOPNOTSUPP) 20508c2ecf20Sopenharmony_ci cmd->ret = ret; 20518c2ecf20Sopenharmony_ci else 20528c2ecf20Sopenharmony_ci cmd->ret = ret ? -EIO : 0; 20538c2ecf20Sopenharmony_ci if (likely(!blk_should_fake_timeout(rq->q))) 20548c2ecf20Sopenharmony_ci blk_mq_complete_request(rq); 20558c2ecf20Sopenharmony_ci } 20568c2ecf20Sopenharmony_ci} 20578c2ecf20Sopenharmony_ci 20588c2ecf20Sopenharmony_cistatic void loop_queue_work(struct kthread_work *work) 20598c2ecf20Sopenharmony_ci{ 20608c2ecf20Sopenharmony_ci struct loop_cmd *cmd = 20618c2ecf20Sopenharmony_ci container_of(work, struct loop_cmd, work); 20628c2ecf20Sopenharmony_ci 20638c2ecf20Sopenharmony_ci loop_handle_cmd(cmd); 20648c2ecf20Sopenharmony_ci} 20658c2ecf20Sopenharmony_ci 20668c2ecf20Sopenharmony_cistatic int loop_init_request(struct blk_mq_tag_set *set, struct request *rq, 20678c2ecf20Sopenharmony_ci unsigned int hctx_idx, unsigned int numa_node) 20688c2ecf20Sopenharmony_ci{ 20698c2ecf20Sopenharmony_ci struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq); 20708c2ecf20Sopenharmony_ci 20718c2ecf20Sopenharmony_ci kthread_init_work(&cmd->work, loop_queue_work); 20728c2ecf20Sopenharmony_ci return 0; 20738c2ecf20Sopenharmony_ci} 20748c2ecf20Sopenharmony_ci 20758c2ecf20Sopenharmony_cistatic const struct blk_mq_ops loop_mq_ops = { 20768c2ecf20Sopenharmony_ci .queue_rq = loop_queue_rq, 20778c2ecf20Sopenharmony_ci .init_request = loop_init_request, 20788c2ecf20Sopenharmony_ci .complete = lo_complete_rq, 20798c2ecf20Sopenharmony_ci}; 20808c2ecf20Sopenharmony_ci 20818c2ecf20Sopenharmony_cistatic int loop_add(struct loop_device **l, int i) 20828c2ecf20Sopenharmony_ci{ 20838c2ecf20Sopenharmony_ci struct loop_device *lo; 20848c2ecf20Sopenharmony_ci struct gendisk *disk; 20858c2ecf20Sopenharmony_ci int err; 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci err = -ENOMEM; 20888c2ecf20Sopenharmony_ci lo = kzalloc(sizeof(*lo), GFP_KERNEL); 20898c2ecf20Sopenharmony_ci if (!lo) 20908c2ecf20Sopenharmony_ci goto out; 20918c2ecf20Sopenharmony_ci 20928c2ecf20Sopenharmony_ci lo->lo_state = Lo_unbound; 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci /* allocate id, if @id >= 0, we're requesting that specific id */ 20958c2ecf20Sopenharmony_ci if (i >= 0) { 20968c2ecf20Sopenharmony_ci err = idr_alloc(&loop_index_idr, lo, i, i + 1, GFP_KERNEL); 20978c2ecf20Sopenharmony_ci if (err == -ENOSPC) 20988c2ecf20Sopenharmony_ci err = -EEXIST; 20998c2ecf20Sopenharmony_ci } else { 21008c2ecf20Sopenharmony_ci err = idr_alloc(&loop_index_idr, lo, 0, 0, GFP_KERNEL); 21018c2ecf20Sopenharmony_ci } 21028c2ecf20Sopenharmony_ci if (err < 0) 21038c2ecf20Sopenharmony_ci goto out_free_dev; 21048c2ecf20Sopenharmony_ci i = err; 21058c2ecf20Sopenharmony_ci 21068c2ecf20Sopenharmony_ci err = -ENOMEM; 21078c2ecf20Sopenharmony_ci lo->tag_set.ops = &loop_mq_ops; 21088c2ecf20Sopenharmony_ci lo->tag_set.nr_hw_queues = 1; 21098c2ecf20Sopenharmony_ci lo->tag_set.queue_depth = 128; 21108c2ecf20Sopenharmony_ci lo->tag_set.numa_node = NUMA_NO_NODE; 21118c2ecf20Sopenharmony_ci lo->tag_set.cmd_size = sizeof(struct loop_cmd); 21128c2ecf20Sopenharmony_ci lo->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_STACKING | 21138c2ecf20Sopenharmony_ci BLK_MQ_F_NO_SCHED_BY_DEFAULT; 21148c2ecf20Sopenharmony_ci lo->tag_set.driver_data = lo; 21158c2ecf20Sopenharmony_ci 21168c2ecf20Sopenharmony_ci err = blk_mq_alloc_tag_set(&lo->tag_set); 21178c2ecf20Sopenharmony_ci if (err) 21188c2ecf20Sopenharmony_ci goto out_free_idr; 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci lo->lo_queue = blk_mq_init_queue(&lo->tag_set); 21218c2ecf20Sopenharmony_ci if (IS_ERR(lo->lo_queue)) { 21228c2ecf20Sopenharmony_ci err = PTR_ERR(lo->lo_queue); 21238c2ecf20Sopenharmony_ci goto out_cleanup_tags; 21248c2ecf20Sopenharmony_ci } 21258c2ecf20Sopenharmony_ci lo->lo_queue->queuedata = lo; 21268c2ecf20Sopenharmony_ci 21278c2ecf20Sopenharmony_ci blk_queue_max_hw_sectors(lo->lo_queue, BLK_DEF_MAX_SECTORS); 21288c2ecf20Sopenharmony_ci 21298c2ecf20Sopenharmony_ci /* 21308c2ecf20Sopenharmony_ci * By default, we do buffer IO, so it doesn't make sense to enable 21318c2ecf20Sopenharmony_ci * merge because the I/O submitted to backing file is handled page by 21328c2ecf20Sopenharmony_ci * page. For directio mode, merge does help to dispatch bigger request 21338c2ecf20Sopenharmony_ci * to underlayer disk. We will enable merge once directio is enabled. 21348c2ecf20Sopenharmony_ci */ 21358c2ecf20Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_NOMERGES, lo->lo_queue); 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci err = -ENOMEM; 21388c2ecf20Sopenharmony_ci disk = lo->lo_disk = alloc_disk(1 << part_shift); 21398c2ecf20Sopenharmony_ci if (!disk) 21408c2ecf20Sopenharmony_ci goto out_free_queue; 21418c2ecf20Sopenharmony_ci 21428c2ecf20Sopenharmony_ci /* 21438c2ecf20Sopenharmony_ci * Disable partition scanning by default. The in-kernel partition 21448c2ecf20Sopenharmony_ci * scanning can be requested individually per-device during its 21458c2ecf20Sopenharmony_ci * setup. Userspace can always add and remove partitions from all 21468c2ecf20Sopenharmony_ci * devices. The needed partition minors are allocated from the 21478c2ecf20Sopenharmony_ci * extended minor space, the main loop device numbers will continue 21488c2ecf20Sopenharmony_ci * to match the loop minors, regardless of the number of partitions 21498c2ecf20Sopenharmony_ci * used. 21508c2ecf20Sopenharmony_ci * 21518c2ecf20Sopenharmony_ci * If max_part is given, partition scanning is globally enabled for 21528c2ecf20Sopenharmony_ci * all loop devices. The minors for the main loop devices will be 21538c2ecf20Sopenharmony_ci * multiples of max_part. 21548c2ecf20Sopenharmony_ci * 21558c2ecf20Sopenharmony_ci * Note: Global-for-all-devices, set-only-at-init, read-only module 21568c2ecf20Sopenharmony_ci * parameteters like 'max_loop' and 'max_part' make things needlessly 21578c2ecf20Sopenharmony_ci * complicated, are too static, inflexible and may surprise 21588c2ecf20Sopenharmony_ci * userspace tools. Parameters like this in general should be avoided. 21598c2ecf20Sopenharmony_ci */ 21608c2ecf20Sopenharmony_ci if (!part_shift) 21618c2ecf20Sopenharmony_ci disk->flags |= GENHD_FL_NO_PART_SCAN; 21628c2ecf20Sopenharmony_ci disk->flags |= GENHD_FL_EXT_DEVT; 21638c2ecf20Sopenharmony_ci atomic_set(&lo->lo_refcnt, 0); 21648c2ecf20Sopenharmony_ci lo->lo_number = i; 21658c2ecf20Sopenharmony_ci spin_lock_init(&lo->lo_lock); 21668c2ecf20Sopenharmony_ci disk->major = LOOP_MAJOR; 21678c2ecf20Sopenharmony_ci disk->first_minor = i << part_shift; 21688c2ecf20Sopenharmony_ci disk->fops = &lo_fops; 21698c2ecf20Sopenharmony_ci disk->private_data = lo; 21708c2ecf20Sopenharmony_ci disk->queue = lo->lo_queue; 21718c2ecf20Sopenharmony_ci sprintf(disk->disk_name, "loop%d", i); 21728c2ecf20Sopenharmony_ci add_disk(disk); 21738c2ecf20Sopenharmony_ci *l = lo; 21748c2ecf20Sopenharmony_ci return lo->lo_number; 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ciout_free_queue: 21778c2ecf20Sopenharmony_ci blk_cleanup_queue(lo->lo_queue); 21788c2ecf20Sopenharmony_ciout_cleanup_tags: 21798c2ecf20Sopenharmony_ci blk_mq_free_tag_set(&lo->tag_set); 21808c2ecf20Sopenharmony_ciout_free_idr: 21818c2ecf20Sopenharmony_ci idr_remove(&loop_index_idr, i); 21828c2ecf20Sopenharmony_ciout_free_dev: 21838c2ecf20Sopenharmony_ci kfree(lo); 21848c2ecf20Sopenharmony_ciout: 21858c2ecf20Sopenharmony_ci return err; 21868c2ecf20Sopenharmony_ci} 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_cistatic void loop_remove(struct loop_device *lo) 21898c2ecf20Sopenharmony_ci{ 21908c2ecf20Sopenharmony_ci del_gendisk(lo->lo_disk); 21918c2ecf20Sopenharmony_ci blk_cleanup_queue(lo->lo_queue); 21928c2ecf20Sopenharmony_ci blk_mq_free_tag_set(&lo->tag_set); 21938c2ecf20Sopenharmony_ci put_disk(lo->lo_disk); 21948c2ecf20Sopenharmony_ci kfree(lo); 21958c2ecf20Sopenharmony_ci} 21968c2ecf20Sopenharmony_ci 21978c2ecf20Sopenharmony_cistatic int find_free_cb(int id, void *ptr, void *data) 21988c2ecf20Sopenharmony_ci{ 21998c2ecf20Sopenharmony_ci struct loop_device *lo = ptr; 22008c2ecf20Sopenharmony_ci struct loop_device **l = data; 22018c2ecf20Sopenharmony_ci 22028c2ecf20Sopenharmony_ci if (lo->lo_state == Lo_unbound) { 22038c2ecf20Sopenharmony_ci *l = lo; 22048c2ecf20Sopenharmony_ci return 1; 22058c2ecf20Sopenharmony_ci } 22068c2ecf20Sopenharmony_ci return 0; 22078c2ecf20Sopenharmony_ci} 22088c2ecf20Sopenharmony_ci 22098c2ecf20Sopenharmony_cistatic int loop_lookup(struct loop_device **l, int i) 22108c2ecf20Sopenharmony_ci{ 22118c2ecf20Sopenharmony_ci struct loop_device *lo; 22128c2ecf20Sopenharmony_ci int ret = -ENODEV; 22138c2ecf20Sopenharmony_ci 22148c2ecf20Sopenharmony_ci if (i < 0) { 22158c2ecf20Sopenharmony_ci int err; 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci err = idr_for_each(&loop_index_idr, &find_free_cb, &lo); 22188c2ecf20Sopenharmony_ci if (err == 1) { 22198c2ecf20Sopenharmony_ci *l = lo; 22208c2ecf20Sopenharmony_ci ret = lo->lo_number; 22218c2ecf20Sopenharmony_ci } 22228c2ecf20Sopenharmony_ci goto out; 22238c2ecf20Sopenharmony_ci } 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_ci /* lookup and return a specific i */ 22268c2ecf20Sopenharmony_ci lo = idr_find(&loop_index_idr, i); 22278c2ecf20Sopenharmony_ci if (lo) { 22288c2ecf20Sopenharmony_ci *l = lo; 22298c2ecf20Sopenharmony_ci ret = lo->lo_number; 22308c2ecf20Sopenharmony_ci } 22318c2ecf20Sopenharmony_ciout: 22328c2ecf20Sopenharmony_ci return ret; 22338c2ecf20Sopenharmony_ci} 22348c2ecf20Sopenharmony_ci 22358c2ecf20Sopenharmony_cistatic struct kobject *loop_probe(dev_t dev, int *part, void *data) 22368c2ecf20Sopenharmony_ci{ 22378c2ecf20Sopenharmony_ci struct loop_device *lo; 22388c2ecf20Sopenharmony_ci struct kobject *kobj; 22398c2ecf20Sopenharmony_ci int err; 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci mutex_lock(&loop_ctl_mutex); 22428c2ecf20Sopenharmony_ci err = loop_lookup(&lo, MINOR(dev) >> part_shift); 22438c2ecf20Sopenharmony_ci if (err < 0) 22448c2ecf20Sopenharmony_ci err = loop_add(&lo, MINOR(dev) >> part_shift); 22458c2ecf20Sopenharmony_ci if (err < 0) 22468c2ecf20Sopenharmony_ci kobj = NULL; 22478c2ecf20Sopenharmony_ci else 22488c2ecf20Sopenharmony_ci kobj = get_disk_and_module(lo->lo_disk); 22498c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 22508c2ecf20Sopenharmony_ci 22518c2ecf20Sopenharmony_ci *part = 0; 22528c2ecf20Sopenharmony_ci return kobj; 22538c2ecf20Sopenharmony_ci} 22548c2ecf20Sopenharmony_ci 22558c2ecf20Sopenharmony_cistatic long loop_control_ioctl(struct file *file, unsigned int cmd, 22568c2ecf20Sopenharmony_ci unsigned long parm) 22578c2ecf20Sopenharmony_ci{ 22588c2ecf20Sopenharmony_ci struct loop_device *lo; 22598c2ecf20Sopenharmony_ci int ret; 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci ret = mutex_lock_killable(&loop_ctl_mutex); 22628c2ecf20Sopenharmony_ci if (ret) 22638c2ecf20Sopenharmony_ci return ret; 22648c2ecf20Sopenharmony_ci 22658c2ecf20Sopenharmony_ci ret = -ENOSYS; 22668c2ecf20Sopenharmony_ci switch (cmd) { 22678c2ecf20Sopenharmony_ci case LOOP_CTL_ADD: 22688c2ecf20Sopenharmony_ci ret = loop_lookup(&lo, parm); 22698c2ecf20Sopenharmony_ci if (ret >= 0) { 22708c2ecf20Sopenharmony_ci ret = -EEXIST; 22718c2ecf20Sopenharmony_ci break; 22728c2ecf20Sopenharmony_ci } 22738c2ecf20Sopenharmony_ci ret = loop_add(&lo, parm); 22748c2ecf20Sopenharmony_ci break; 22758c2ecf20Sopenharmony_ci case LOOP_CTL_REMOVE: 22768c2ecf20Sopenharmony_ci ret = loop_lookup(&lo, parm); 22778c2ecf20Sopenharmony_ci if (ret < 0) 22788c2ecf20Sopenharmony_ci break; 22798c2ecf20Sopenharmony_ci if (lo->lo_state != Lo_unbound) { 22808c2ecf20Sopenharmony_ci ret = -EBUSY; 22818c2ecf20Sopenharmony_ci break; 22828c2ecf20Sopenharmony_ci } 22838c2ecf20Sopenharmony_ci if (atomic_read(&lo->lo_refcnt) > 0) { 22848c2ecf20Sopenharmony_ci ret = -EBUSY; 22858c2ecf20Sopenharmony_ci break; 22868c2ecf20Sopenharmony_ci } 22878c2ecf20Sopenharmony_ci lo->lo_disk->private_data = NULL; 22888c2ecf20Sopenharmony_ci idr_remove(&loop_index_idr, lo->lo_number); 22898c2ecf20Sopenharmony_ci loop_remove(lo); 22908c2ecf20Sopenharmony_ci break; 22918c2ecf20Sopenharmony_ci case LOOP_CTL_GET_FREE: 22928c2ecf20Sopenharmony_ci ret = loop_lookup(&lo, -1); 22938c2ecf20Sopenharmony_ci if (ret >= 0) 22948c2ecf20Sopenharmony_ci break; 22958c2ecf20Sopenharmony_ci ret = loop_add(&lo, -1); 22968c2ecf20Sopenharmony_ci } 22978c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 22988c2ecf20Sopenharmony_ci 22998c2ecf20Sopenharmony_ci return ret; 23008c2ecf20Sopenharmony_ci} 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_cistatic const struct file_operations loop_ctl_fops = { 23038c2ecf20Sopenharmony_ci .open = nonseekable_open, 23048c2ecf20Sopenharmony_ci .unlocked_ioctl = loop_control_ioctl, 23058c2ecf20Sopenharmony_ci .compat_ioctl = loop_control_ioctl, 23068c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 23078c2ecf20Sopenharmony_ci .llseek = noop_llseek, 23088c2ecf20Sopenharmony_ci}; 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_cistatic struct miscdevice loop_misc = { 23118c2ecf20Sopenharmony_ci .minor = LOOP_CTRL_MINOR, 23128c2ecf20Sopenharmony_ci .name = "loop-control", 23138c2ecf20Sopenharmony_ci .fops = &loop_ctl_fops, 23148c2ecf20Sopenharmony_ci}; 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ciMODULE_ALIAS_MISCDEV(LOOP_CTRL_MINOR); 23178c2ecf20Sopenharmony_ciMODULE_ALIAS("devname:loop-control"); 23188c2ecf20Sopenharmony_ci 23198c2ecf20Sopenharmony_cistatic int __init loop_init(void) 23208c2ecf20Sopenharmony_ci{ 23218c2ecf20Sopenharmony_ci int i, nr; 23228c2ecf20Sopenharmony_ci unsigned long range; 23238c2ecf20Sopenharmony_ci struct loop_device *lo; 23248c2ecf20Sopenharmony_ci int err; 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_ci part_shift = 0; 23278c2ecf20Sopenharmony_ci if (max_part > 0) { 23288c2ecf20Sopenharmony_ci part_shift = fls(max_part); 23298c2ecf20Sopenharmony_ci 23308c2ecf20Sopenharmony_ci /* 23318c2ecf20Sopenharmony_ci * Adjust max_part according to part_shift as it is exported 23328c2ecf20Sopenharmony_ci * to user space so that user can decide correct minor number 23338c2ecf20Sopenharmony_ci * if [s]he want to create more devices. 23348c2ecf20Sopenharmony_ci * 23358c2ecf20Sopenharmony_ci * Note that -1 is required because partition 0 is reserved 23368c2ecf20Sopenharmony_ci * for the whole disk. 23378c2ecf20Sopenharmony_ci */ 23388c2ecf20Sopenharmony_ci max_part = (1UL << part_shift) - 1; 23398c2ecf20Sopenharmony_ci } 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_ci if ((1UL << part_shift) > DISK_MAX_PARTS) { 23428c2ecf20Sopenharmony_ci err = -EINVAL; 23438c2ecf20Sopenharmony_ci goto err_out; 23448c2ecf20Sopenharmony_ci } 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci if (max_loop > 1UL << (MINORBITS - part_shift)) { 23478c2ecf20Sopenharmony_ci err = -EINVAL; 23488c2ecf20Sopenharmony_ci goto err_out; 23498c2ecf20Sopenharmony_ci } 23508c2ecf20Sopenharmony_ci 23518c2ecf20Sopenharmony_ci /* 23528c2ecf20Sopenharmony_ci * If max_loop is specified, create that many devices upfront. 23538c2ecf20Sopenharmony_ci * This also becomes a hard limit. If max_loop is not specified, 23548c2ecf20Sopenharmony_ci * create CONFIG_BLK_DEV_LOOP_MIN_COUNT loop devices at module 23558c2ecf20Sopenharmony_ci * init time. Loop devices can be requested on-demand with the 23568c2ecf20Sopenharmony_ci * /dev/loop-control interface, or be instantiated by accessing 23578c2ecf20Sopenharmony_ci * a 'dead' device node. 23588c2ecf20Sopenharmony_ci */ 23598c2ecf20Sopenharmony_ci if (max_loop) { 23608c2ecf20Sopenharmony_ci nr = max_loop; 23618c2ecf20Sopenharmony_ci range = max_loop << part_shift; 23628c2ecf20Sopenharmony_ci } else { 23638c2ecf20Sopenharmony_ci nr = CONFIG_BLK_DEV_LOOP_MIN_COUNT; 23648c2ecf20Sopenharmony_ci range = 1UL << MINORBITS; 23658c2ecf20Sopenharmony_ci } 23668c2ecf20Sopenharmony_ci 23678c2ecf20Sopenharmony_ci err = misc_register(&loop_misc); 23688c2ecf20Sopenharmony_ci if (err < 0) 23698c2ecf20Sopenharmony_ci goto err_out; 23708c2ecf20Sopenharmony_ci 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci if (register_blkdev(LOOP_MAJOR, "loop")) { 23738c2ecf20Sopenharmony_ci err = -EIO; 23748c2ecf20Sopenharmony_ci goto misc_out; 23758c2ecf20Sopenharmony_ci } 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci blk_register_region(MKDEV(LOOP_MAJOR, 0), range, 23788c2ecf20Sopenharmony_ci THIS_MODULE, loop_probe, NULL, NULL); 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci /* pre-create number of devices given by config or max_loop */ 23818c2ecf20Sopenharmony_ci mutex_lock(&loop_ctl_mutex); 23828c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) 23838c2ecf20Sopenharmony_ci loop_add(&lo, i); 23848c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci printk(KERN_INFO "loop: module loaded\n"); 23878c2ecf20Sopenharmony_ci return 0; 23888c2ecf20Sopenharmony_ci 23898c2ecf20Sopenharmony_cimisc_out: 23908c2ecf20Sopenharmony_ci misc_deregister(&loop_misc); 23918c2ecf20Sopenharmony_cierr_out: 23928c2ecf20Sopenharmony_ci return err; 23938c2ecf20Sopenharmony_ci} 23948c2ecf20Sopenharmony_ci 23958c2ecf20Sopenharmony_cistatic int loop_exit_cb(int id, void *ptr, void *data) 23968c2ecf20Sopenharmony_ci{ 23978c2ecf20Sopenharmony_ci struct loop_device *lo = ptr; 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci loop_remove(lo); 24008c2ecf20Sopenharmony_ci return 0; 24018c2ecf20Sopenharmony_ci} 24028c2ecf20Sopenharmony_ci 24038c2ecf20Sopenharmony_cistatic void __exit loop_exit(void) 24048c2ecf20Sopenharmony_ci{ 24058c2ecf20Sopenharmony_ci unsigned long range; 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci range = max_loop ? max_loop << part_shift : 1UL << MINORBITS; 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_ci mutex_lock(&loop_ctl_mutex); 24108c2ecf20Sopenharmony_ci 24118c2ecf20Sopenharmony_ci idr_for_each(&loop_index_idr, &loop_exit_cb, NULL); 24128c2ecf20Sopenharmony_ci idr_destroy(&loop_index_idr); 24138c2ecf20Sopenharmony_ci 24148c2ecf20Sopenharmony_ci blk_unregister_region(MKDEV(LOOP_MAJOR, 0), range); 24158c2ecf20Sopenharmony_ci unregister_blkdev(LOOP_MAJOR, "loop"); 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci misc_deregister(&loop_misc); 24188c2ecf20Sopenharmony_ci 24198c2ecf20Sopenharmony_ci mutex_unlock(&loop_ctl_mutex); 24208c2ecf20Sopenharmony_ci} 24218c2ecf20Sopenharmony_ci 24228c2ecf20Sopenharmony_cimodule_init(loop_init); 24238c2ecf20Sopenharmony_cimodule_exit(loop_exit); 24248c2ecf20Sopenharmony_ci 24258c2ecf20Sopenharmony_ci#ifndef MODULE 24268c2ecf20Sopenharmony_cistatic int __init max_loop_setup(char *str) 24278c2ecf20Sopenharmony_ci{ 24288c2ecf20Sopenharmony_ci max_loop = simple_strtol(str, NULL, 0); 24298c2ecf20Sopenharmony_ci return 1; 24308c2ecf20Sopenharmony_ci} 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci__setup("max_loop=", max_loop_setup); 24338c2ecf20Sopenharmony_ci#endif 2434