for-6.5/block-2023-06-23

-----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCAAuFiEEwPw5LcreJtl1+l5K99NY+ylx4KYFAmSV8dwQHGF4Ym9lQGtl
 cm5lbC5kawAKCRD301j7KXHgpilGD/9Yys1oxIXJpRf00fzrylAlBthRxMjFQVWw
 zAut106hAQiBHvU8IkmGA3MvEFVHxtzwYhHI7IR8K3aZBIqscweCqmVI9JyogJw9
 U9Twnzel47VmuKdM94FeoN+hbj1fP8EWTjzmy67/zEEfFCdmHvNlMi3lSrGYIpFy
 39LxTB99Y4UarM5PtWbes37GYYljzMSWKuo4AfBkvq1eQa+sZ0Vq2xAABKq3UM7f
 apqhgHtkJooRePDP0eQp+kAyyVMgW2jIK+oIdJDxNF3CKTu2w40RzaYz6fp+jVSU
 H4R/xS59GW4/xql+VBJDh/qJg9K62DPPYjlW8BmSR8+IjvfFpsyH3/MacE50CD3P
 20fs/Mnj49H79fDrQEHJI53cOOb2EmUitbwLbvOcColNTPpt8loBtdQxjF2RMU8R
 Nyort9DJPFclYCxky1LYg1CNEC2Ln4Zy/jD47wPvqRmOQphOoVlV/hPnOEqvjaZC
 49Vn70W2DeE9cXvYI7ha+XIg6/oj+Gs3iusEbV08Ci7EAtXgI+ZUUsQ97K8UNiUh
 h2lqSJtuI7lBpYP9sf+BeCch5UCC+xGYyTdoM5f58lehWBBPtbs0g7S9RyRyOYxe
 n+yxEUo3dAGzJ/xsKAjinbZfeWIpr0b1TkAh4w3Cq/BKzRr9Bp8lBAxYuancbQ+Y
 1ADPteUOTA==
 =zP4Y
 -----END PGP SIGNATURE-----

Merge tag 'for-6.5/block-2023-06-23' of git://git.kernel.dk/linux

Pull block updates from Jens Axboe:

 - NVMe pull request via Keith:
      - Various cleanups all around (Irvin, Chaitanya, Christophe)
      - Better struct packing (Christophe JAILLET)
      - Reduce controller error logs for optional commands (Keith)
      - Support for >=64KiB block sizes (Daniel Gomez)
      - Fabrics fixes and code organization (Max, Chaitanya, Daniel
        Wagner)

 - bcache updates via Coly:
      - Fix a race at init time (Mingzhe Zou)
      - Misc fixes and cleanups (Andrea, Thomas, Zheng, Ye)

 - use page pinning in the block layer for dio (David)

 - convert old block dio code to page pinning (David, Christoph)

 - cleanups for pktcdvd (Andy)

 - cleanups for rnbd (Guoqing)

 - use the unchecked __bio_add_page() for the initial single page
   additions (Johannes)

 - fix overflows in the Amiga partition handling code (Michael)

 - improve mq-deadline zoned device support (Bart)

 - keep passthrough requests out of the IO schedulers (Christoph, Ming)

 - improve support for flush requests, making them less special to deal
   with (Christoph)

 - add bdev holder ops and shutdown methods (Christoph)

 - fix the name_to_dev_t() situation and use cases (Christoph)

 - decouple the block open flags from fmode_t (Christoph)

 - ublk updates and cleanups, including adding user copy support (Ming)

 - BFQ sanity checking (Bart)

 - convert brd from radix to xarray (Pankaj)

 - constify various structures (Thomas, Ivan)

 - more fine grained persistent reservation ioctl capability checks
   (Jingbo)

 - misc fixes and cleanups (Arnd, Azeem, Demi, Ed, Hengqi, Hou, Jan,
   Jordy, Li, Min, Yu, Zhong, Waiman)

* tag 'for-6.5/block-2023-06-23' of git://git.kernel.dk/linux: (266 commits)
  scsi/sg: don't grab scsi host module reference
  ext4: Fix warning in blkdev_put()
  block: don't return -EINVAL for not found names in devt_from_devname
  cdrom: Fix spectre-v1 gadget
  block: Improve kernel-doc headers
  blk-mq: don't insert passthrough request into sw queue
  bsg: make bsg_class a static const structure
  ublk: make ublk_chr_class a static const structure
  aoe: make aoe_class a static const structure
  block/rnbd: make all 'class' structures const
  block: fix the exclusive open mask in disk_scan_partitions
  block: add overflow checks for Amiga partition support
  block: change all __u32 annotations to __be32 in affs_hardblocks.h
  block: fix signed int overflow in Amiga partition support
  block: add capacity validation in bdev_add_partition()
  block: fine-granular CAP_SYS_ADMIN for Persistent Reservation
  block: disallow Persistent Reservation on partitions
  reiserfs: fix blkdev_put() warning from release_journal_dev()
  block: fix wrong mode for blkdev_get_by_dev() from disk_scan_partitions()
  block: document the holder argument to blkdev_get_by_path
  ...
This commit is contained in:
Linus Torvalds 2023-06-26 12:47:20 -07:00
commit a0433f8cae
218 changed files with 4750 additions and 3887 deletions

View file

@ -508,9 +508,6 @@ cache_miss_collisions
cache miss, but raced with a write and data was already present (usually 0 cache miss, but raced with a write and data was already present (usually 0
since the synchronization for cache misses was rewritten) since the synchronization for cache misses was rewritten)
cache_readaheads
Count of times readahead occurred.
Sysfs - cache set Sysfs - cache set
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~

View file

@ -2022,31 +2022,33 @@ that attribute:
no-change no-change
Do not modify the I/O priority class. Do not modify the I/O priority class.
none-to-rt promote-to-rt
For requests that do not have an I/O priority class (NONE), For requests that have a non-RT I/O priority class, change it into RT.
change the I/O priority class into RT. Do not modify Also change the priority level of these requests to 4. Do not modify
the I/O priority class of other requests. the I/O priority of requests that have priority class RT.
restrict-to-be restrict-to-be
For requests that do not have an I/O priority class or that have I/O For requests that do not have an I/O priority class or that have I/O
priority class RT, change it into BE. Do not modify the I/O priority priority class RT, change it into BE. Also change the priority level
class of requests that have priority class IDLE. of these requests to 0. Do not modify the I/O priority class of
requests that have priority class IDLE.
idle idle
Change the I/O priority class of all requests into IDLE, the lowest Change the I/O priority class of all requests into IDLE, the lowest
I/O priority class. I/O priority class.
none-to-rt
Deprecated. Just an alias for promote-to-rt.
The following numerical values are associated with the I/O priority policies: The following numerical values are associated with the I/O priority policies:
+-------------+---+ +----------------+---+
| no-change | 0 | | no-change | 0 |
+-------------+---+ +----------------+---+
| none-to-rt | 1 | | rt-to-be | 2 |
+-------------+---+ +----------------+---+
| rt-to-be | 2 | | all-to-idle | 3 |
+-------------+---+ +----------------+---+
| all-to-idle | 3 |
+-------------+---+
The numerical value that corresponds to each I/O priority class is as follows: The numerical value that corresponds to each I/O priority class is as follows:
@ -2062,9 +2064,13 @@ The numerical value that corresponds to each I/O priority class is as follows:
The algorithm to set the I/O priority class for a request is as follows: The algorithm to set the I/O priority class for a request is as follows:
- Translate the I/O priority class policy into a number. - If I/O priority class policy is promote-to-rt, change the request I/O
- Change the request I/O priority class into the maximum of the I/O priority priority class to IOPRIO_CLASS_RT and change the request I/O priority
class policy number and the numerical I/O priority class. level to 4.
- If I/O priorityt class is not promote-to-rt, translate the I/O priority
class policy into a number, then change the request I/O priority class
into the maximum of the I/O priority class policy number and the numerical
I/O priority class.
PID PID
--- ---

View file

@ -5452,7 +5452,12 @@
port and the regular usb controller gets disabled. port and the regular usb controller gets disabled.
root= [KNL] Root filesystem root= [KNL] Root filesystem
See name_to_dev_t comment in init/do_mounts.c. Usually this a a block device specifier of some kind,
see the early_lookup_bdev comment in
block/early-lookup.c for details.
Alternatively this can be "ram" for the legacy initial
ramdisk, "nfs" and "cifs" for root on a network file
system, or "mtd" and "ubi" for mounting from raw flash.
rootdelay= [KNL] Delay (in seconds) to pause before attempting to rootdelay= [KNL] Delay (in seconds) to pause before attempting to
mount the root filesystem mount the root filesystem

View file

@ -112,6 +112,12 @@ pages:
This also leads to limitations: there are only 31-10==21 bits available for a This also leads to limitations: there are only 31-10==21 bits available for a
counter that increments 10 bits at a time. counter that increments 10 bits at a time.
* Because of that limitation, special handling is applied to the zero pages
when using FOLL_PIN. We only pretend to pin a zero page - we don't alter its
refcount or pincount at all (it is permanent, so there's no need). The
unpinning functions also don't do anything to a zero page. This is
transparent to the caller.
* Callers must specifically request "dma-pinned tracking of pages". In other * Callers must specifically request "dma-pinned tracking of pages". In other
words, just calling get_user_pages() will not suffice; a new set of functions, words, just calling get_user_pages() will not suffice; a new set of functions,
pin_user_page() and related, must be used. pin_user_page() and related, must be used.

View file

@ -658,7 +658,7 @@ setup_arch(char **cmdline_p)
#endif #endif
/* Default root filesystem to sda2. */ /* Default root filesystem to sda2. */
ROOT_DEV = Root_SDA2; ROOT_DEV = MKDEV(SCSI_DISK0_MAJOR, 2);
#ifdef CONFIG_EISA #ifdef CONFIG_EISA
/* FIXME: only set this when we actually have EISA in this box? */ /* FIXME: only set this when we actually have EISA in this box? */

View file

@ -627,7 +627,7 @@ setup_arch (char **cmdline_p)
* is physical disk 1 partition 1 and the Linux root disk is * is physical disk 1 partition 1 and the Linux root disk is
* physical disk 1 partition 2. * physical disk 1 partition 2.
*/ */
ROOT_DEV = Root_SDA2; /* default to second partition on first drive */ ROOT_DEV = MKDEV(SCSI_DISK0_MAJOR, 2);
if (is_uv_system()) if (is_uv_system())
uv_setup(cmdline_p); uv_setup(cmdline_p);

View file

@ -76,7 +76,8 @@ int pmac_newworld;
static int current_root_goodness = -1; static int current_root_goodness = -1;
#define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ /* sda1 - slightly silly choice */
#define DEFAULT_ROOT_DEVICE MKDEV(SCSI_DISK0_MAJOR, 1)
sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN; sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN;
EXPORT_SYMBOL(sys_ctrler); EXPORT_SYMBOL(sys_ctrler);

View file

@ -108,9 +108,9 @@ static inline void ubd_set_bit(__u64 bit, unsigned char *data)
static DEFINE_MUTEX(ubd_lock); static DEFINE_MUTEX(ubd_lock);
static DEFINE_MUTEX(ubd_mutex); /* replaces BKL, might not be needed */ static DEFINE_MUTEX(ubd_mutex); /* replaces BKL, might not be needed */
static int ubd_open(struct block_device *bdev, fmode_t mode); static int ubd_open(struct gendisk *disk, blk_mode_t mode);
static void ubd_release(struct gendisk *disk, fmode_t mode); static void ubd_release(struct gendisk *disk);
static int ubd_ioctl(struct block_device *bdev, fmode_t mode, static int ubd_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long arg); unsigned int cmd, unsigned long arg);
static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo); static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo);
@ -1154,9 +1154,8 @@ static int __init ubd_driver_init(void){
device_initcall(ubd_driver_init); device_initcall(ubd_driver_init);
static int ubd_open(struct block_device *bdev, fmode_t mode) static int ubd_open(struct gendisk *disk, blk_mode_t mode)
{ {
struct gendisk *disk = bdev->bd_disk;
struct ubd *ubd_dev = disk->private_data; struct ubd *ubd_dev = disk->private_data;
int err = 0; int err = 0;
@ -1171,19 +1170,12 @@ static int ubd_open(struct block_device *bdev, fmode_t mode)
} }
ubd_dev->count++; ubd_dev->count++;
set_disk_ro(disk, !ubd_dev->openflags.w); set_disk_ro(disk, !ubd_dev->openflags.w);
/* This should no more be needed. And it didn't work anyway to exclude
* read-write remounting of filesystems.*/
/*if((mode & FMODE_WRITE) && !ubd_dev->openflags.w){
if(--ubd_dev->count == 0) ubd_close_dev(ubd_dev);
err = -EROFS;
}*/
out: out:
mutex_unlock(&ubd_mutex); mutex_unlock(&ubd_mutex);
return err; return err;
} }
static void ubd_release(struct gendisk *disk, fmode_t mode) static void ubd_release(struct gendisk *disk)
{ {
struct ubd *ubd_dev = disk->private_data; struct ubd *ubd_dev = disk->private_data;
@ -1397,7 +1389,7 @@ static int ubd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0; return 0;
} }
static int ubd_ioctl(struct block_device *bdev, fmode_t mode, static int ubd_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
struct ubd *ubd_dev = bdev->bd_disk->private_data; struct ubd *ubd_dev = bdev->bd_disk->private_data;

View file

@ -120,9 +120,9 @@ static void simdisk_submit_bio(struct bio *bio)
bio_endio(bio); bio_endio(bio);
} }
static int simdisk_open(struct block_device *bdev, fmode_t mode) static int simdisk_open(struct gendisk *disk, blk_mode_t mode)
{ {
struct simdisk *dev = bdev->bd_disk->private_data; struct simdisk *dev = disk->private_data;
spin_lock(&dev->lock); spin_lock(&dev->lock);
++dev->users; ++dev->users;
@ -130,7 +130,7 @@ static int simdisk_open(struct block_device *bdev, fmode_t mode)
return 0; return 0;
} }
static void simdisk_release(struct gendisk *disk, fmode_t mode) static void simdisk_release(struct gendisk *disk)
{ {
struct simdisk *dev = disk->private_data; struct simdisk *dev = disk->private_data;
spin_lock(&dev->lock); spin_lock(&dev->lock);

View file

@ -9,7 +9,7 @@ obj-y := bdev.o fops.o bio.o elevator.o blk-core.o blk-sysfs.o \
blk-lib.o blk-mq.o blk-mq-tag.o blk-stat.o \ blk-lib.o blk-mq.o blk-mq-tag.o blk-stat.o \
blk-mq-sysfs.o blk-mq-cpumap.o blk-mq-sched.o ioctl.o \ blk-mq-sysfs.o blk-mq-cpumap.o blk-mq-sched.o ioctl.o \
genhd.o ioprio.o badblocks.o partitions/ blk-rq-qos.o \ genhd.o ioprio.o badblocks.o partitions/ blk-rq-qos.o \
disk-events.o blk-ia-ranges.o disk-events.o blk-ia-ranges.o early-lookup.o
obj-$(CONFIG_BOUNCE) += bounce.o obj-$(CONFIG_BOUNCE) += bounce.o
obj-$(CONFIG_BLK_DEV_BSG_COMMON) += bsg.o obj-$(CONFIG_BLK_DEV_BSG_COMMON) += bsg.o

View file

@ -93,7 +93,7 @@ EXPORT_SYMBOL(invalidate_bdev);
* Drop all buffers & page cache for given bdev range. This function bails * Drop all buffers & page cache for given bdev range. This function bails
* with error if bdev has other exclusive owner (such as filesystem). * with error if bdev has other exclusive owner (such as filesystem).
*/ */
int truncate_bdev_range(struct block_device *bdev, fmode_t mode, int truncate_bdev_range(struct block_device *bdev, blk_mode_t mode,
loff_t lstart, loff_t lend) loff_t lstart, loff_t lend)
{ {
/* /*
@ -101,14 +101,14 @@ int truncate_bdev_range(struct block_device *bdev, fmode_t mode,
* while we discard the buffer cache to avoid discarding buffers * while we discard the buffer cache to avoid discarding buffers
* under live filesystem. * under live filesystem.
*/ */
if (!(mode & FMODE_EXCL)) { if (!(mode & BLK_OPEN_EXCL)) {
int err = bd_prepare_to_claim(bdev, truncate_bdev_range); int err = bd_prepare_to_claim(bdev, truncate_bdev_range, NULL);
if (err) if (err)
goto invalidate; goto invalidate;
} }
truncate_inode_pages_range(bdev->bd_inode->i_mapping, lstart, lend); truncate_inode_pages_range(bdev->bd_inode->i_mapping, lstart, lend);
if (!(mode & FMODE_EXCL)) if (!(mode & BLK_OPEN_EXCL))
bd_abort_claiming(bdev, truncate_bdev_range); bd_abort_claiming(bdev, truncate_bdev_range);
return 0; return 0;
@ -308,7 +308,7 @@ EXPORT_SYMBOL(thaw_bdev);
* pseudo-fs * pseudo-fs
*/ */
static __cacheline_aligned_in_smp DEFINE_SPINLOCK(bdev_lock); static __cacheline_aligned_in_smp DEFINE_MUTEX(bdev_lock);
static struct kmem_cache * bdev_cachep __read_mostly; static struct kmem_cache * bdev_cachep __read_mostly;
static struct inode *bdev_alloc_inode(struct super_block *sb) static struct inode *bdev_alloc_inode(struct super_block *sb)
@ -415,6 +415,7 @@ struct block_device *bdev_alloc(struct gendisk *disk, u8 partno)
bdev = I_BDEV(inode); bdev = I_BDEV(inode);
mutex_init(&bdev->bd_fsfreeze_mutex); mutex_init(&bdev->bd_fsfreeze_mutex);
spin_lock_init(&bdev->bd_size_lock); spin_lock_init(&bdev->bd_size_lock);
mutex_init(&bdev->bd_holder_lock);
bdev->bd_partno = partno; bdev->bd_partno = partno;
bdev->bd_inode = inode; bdev->bd_inode = inode;
bdev->bd_queue = disk->queue; bdev->bd_queue = disk->queue;
@ -463,39 +464,48 @@ long nr_blockdev_pages(void)
/** /**
* bd_may_claim - test whether a block device can be claimed * bd_may_claim - test whether a block device can be claimed
* @bdev: block device of interest * @bdev: block device of interest
* @whole: whole block device containing @bdev, may equal @bdev
* @holder: holder trying to claim @bdev * @holder: holder trying to claim @bdev
* @hops: holder ops
* *
* Test whether @bdev can be claimed by @holder. * Test whether @bdev can be claimed by @holder.
* *
* CONTEXT:
* spin_lock(&bdev_lock).
*
* RETURNS: * RETURNS:
* %true if @bdev can be claimed, %false otherwise. * %true if @bdev can be claimed, %false otherwise.
*/ */
static bool bd_may_claim(struct block_device *bdev, struct block_device *whole, static bool bd_may_claim(struct block_device *bdev, void *holder,
void *holder) const struct blk_holder_ops *hops)
{ {
if (bdev->bd_holder == holder) struct block_device *whole = bdev_whole(bdev);
return true; /* already a holder */
else if (bdev->bd_holder != NULL)
return false; /* held by someone else */
else if (whole == bdev)
return true; /* is a whole device which isn't held */
else if (whole->bd_holder == bd_may_claim) lockdep_assert_held(&bdev_lock);
return true; /* is a partition of a device that is being partitioned */
else if (whole->bd_holder != NULL) if (bdev->bd_holder) {
return false; /* is a partition of a held device */ /*
else * The same holder can always re-claim.
return true; /* is a partition of an un-held device */ */
if (bdev->bd_holder == holder) {
if (WARN_ON_ONCE(bdev->bd_holder_ops != hops))
return false;
return true;
}
return false;
}
/*
* If the whole devices holder is set to bd_may_claim, a partition on
* the device is claimed, but not the whole device.
*/
if (whole != bdev &&
whole->bd_holder && whole->bd_holder != bd_may_claim)
return false;
return true;
} }
/** /**
* bd_prepare_to_claim - claim a block device * bd_prepare_to_claim - claim a block device
* @bdev: block device of interest * @bdev: block device of interest
* @holder: holder trying to claim @bdev * @holder: holder trying to claim @bdev
* @hops: holder ops.
* *
* Claim @bdev. This function fails if @bdev is already claimed by another * Claim @bdev. This function fails if @bdev is already claimed by another
* holder and waits if another claiming is in progress. return, the caller * holder and waits if another claiming is in progress. return, the caller
@ -504,17 +514,18 @@ static bool bd_may_claim(struct block_device *bdev, struct block_device *whole,
* RETURNS: * RETURNS:
* 0 if @bdev can be claimed, -EBUSY otherwise. * 0 if @bdev can be claimed, -EBUSY otherwise.
*/ */
int bd_prepare_to_claim(struct block_device *bdev, void *holder) int bd_prepare_to_claim(struct block_device *bdev, void *holder,
const struct blk_holder_ops *hops)
{ {
struct block_device *whole = bdev_whole(bdev); struct block_device *whole = bdev_whole(bdev);
if (WARN_ON_ONCE(!holder)) if (WARN_ON_ONCE(!holder))
return -EINVAL; return -EINVAL;
retry: retry:
spin_lock(&bdev_lock); mutex_lock(&bdev_lock);
/* if someone else claimed, fail */ /* if someone else claimed, fail */
if (!bd_may_claim(bdev, whole, holder)) { if (!bd_may_claim(bdev, holder, hops)) {
spin_unlock(&bdev_lock); mutex_unlock(&bdev_lock);
return -EBUSY; return -EBUSY;
} }
@ -524,7 +535,7 @@ retry:
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE);
spin_unlock(&bdev_lock); mutex_unlock(&bdev_lock);
schedule(); schedule();
finish_wait(wq, &wait); finish_wait(wq, &wait);
goto retry; goto retry;
@ -532,7 +543,7 @@ retry:
/* yay, all mine */ /* yay, all mine */
whole->bd_claiming = holder; whole->bd_claiming = holder;
spin_unlock(&bdev_lock); mutex_unlock(&bdev_lock);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(bd_prepare_to_claim); /* only for the loop driver */ EXPORT_SYMBOL_GPL(bd_prepare_to_claim); /* only for the loop driver */
@ -550,16 +561,18 @@ static void bd_clear_claiming(struct block_device *whole, void *holder)
* bd_finish_claiming - finish claiming of a block device * bd_finish_claiming - finish claiming of a block device
* @bdev: block device of interest * @bdev: block device of interest
* @holder: holder that has claimed @bdev * @holder: holder that has claimed @bdev
* @hops: block device holder operations
* *
* Finish exclusive open of a block device. Mark the device as exlusively * Finish exclusive open of a block device. Mark the device as exlusively
* open by the holder and wake up all waiters for exclusive open to finish. * open by the holder and wake up all waiters for exclusive open to finish.
*/ */
static void bd_finish_claiming(struct block_device *bdev, void *holder) static void bd_finish_claiming(struct block_device *bdev, void *holder,
const struct blk_holder_ops *hops)
{ {
struct block_device *whole = bdev_whole(bdev); struct block_device *whole = bdev_whole(bdev);
spin_lock(&bdev_lock); mutex_lock(&bdev_lock);
BUG_ON(!bd_may_claim(bdev, whole, holder)); BUG_ON(!bd_may_claim(bdev, holder, hops));
/* /*
* Note that for a whole device bd_holders will be incremented twice, * Note that for a whole device bd_holders will be incremented twice,
* and bd_holder will be set to bd_may_claim before being set to holder * and bd_holder will be set to bd_may_claim before being set to holder
@ -567,9 +580,12 @@ static void bd_finish_claiming(struct block_device *bdev, void *holder)
whole->bd_holders++; whole->bd_holders++;
whole->bd_holder = bd_may_claim; whole->bd_holder = bd_may_claim;
bdev->bd_holders++; bdev->bd_holders++;
mutex_lock(&bdev->bd_holder_lock);
bdev->bd_holder = holder; bdev->bd_holder = holder;
bdev->bd_holder_ops = hops;
mutex_unlock(&bdev->bd_holder_lock);
bd_clear_claiming(whole, holder); bd_clear_claiming(whole, holder);
spin_unlock(&bdev_lock); mutex_unlock(&bdev_lock);
} }
/** /**
@ -583,12 +599,47 @@ static void bd_finish_claiming(struct block_device *bdev, void *holder)
*/ */
void bd_abort_claiming(struct block_device *bdev, void *holder) void bd_abort_claiming(struct block_device *bdev, void *holder)
{ {
spin_lock(&bdev_lock); mutex_lock(&bdev_lock);
bd_clear_claiming(bdev_whole(bdev), holder); bd_clear_claiming(bdev_whole(bdev), holder);
spin_unlock(&bdev_lock); mutex_unlock(&bdev_lock);
} }
EXPORT_SYMBOL(bd_abort_claiming); EXPORT_SYMBOL(bd_abort_claiming);
static void bd_end_claim(struct block_device *bdev, void *holder)
{
struct block_device *whole = bdev_whole(bdev);
bool unblock = false;
/*
* Release a claim on the device. The holder fields are protected with
* bdev_lock. open_mutex is used to synchronize disk_holder unlinking.
*/
mutex_lock(&bdev_lock);
WARN_ON_ONCE(bdev->bd_holder != holder);
WARN_ON_ONCE(--bdev->bd_holders < 0);
WARN_ON_ONCE(--whole->bd_holders < 0);
if (!bdev->bd_holders) {
mutex_lock(&bdev->bd_holder_lock);
bdev->bd_holder = NULL;
bdev->bd_holder_ops = NULL;
mutex_unlock(&bdev->bd_holder_lock);
if (bdev->bd_write_holder)
unblock = true;
}
if (!whole->bd_holders)
whole->bd_holder = NULL;
mutex_unlock(&bdev_lock);
/*
* If this was the last claim, remove holder link and unblock evpoll if
* it was a write holder.
*/
if (unblock) {
disk_unblock_events(bdev->bd_disk);
bdev->bd_write_holder = false;
}
}
static void blkdev_flush_mapping(struct block_device *bdev) static void blkdev_flush_mapping(struct block_device *bdev)
{ {
WARN_ON_ONCE(bdev->bd_holders); WARN_ON_ONCE(bdev->bd_holders);
@ -597,13 +648,13 @@ static void blkdev_flush_mapping(struct block_device *bdev)
bdev_write_inode(bdev); bdev_write_inode(bdev);
} }
static int blkdev_get_whole(struct block_device *bdev, fmode_t mode) static int blkdev_get_whole(struct block_device *bdev, blk_mode_t mode)
{ {
struct gendisk *disk = bdev->bd_disk; struct gendisk *disk = bdev->bd_disk;
int ret; int ret;
if (disk->fops->open) { if (disk->fops->open) {
ret = disk->fops->open(bdev, mode); ret = disk->fops->open(disk, mode);
if (ret) { if (ret) {
/* avoid ghost partitions on a removed medium */ /* avoid ghost partitions on a removed medium */
if (ret == -ENOMEDIUM && if (ret == -ENOMEDIUM &&
@ -621,22 +672,19 @@ static int blkdev_get_whole(struct block_device *bdev, fmode_t mode)
return 0; return 0;
} }
static void blkdev_put_whole(struct block_device *bdev, fmode_t mode) static void blkdev_put_whole(struct block_device *bdev)
{ {
if (atomic_dec_and_test(&bdev->bd_openers)) if (atomic_dec_and_test(&bdev->bd_openers))
blkdev_flush_mapping(bdev); blkdev_flush_mapping(bdev);
if (bdev->bd_disk->fops->release) if (bdev->bd_disk->fops->release)
bdev->bd_disk->fops->release(bdev->bd_disk, mode); bdev->bd_disk->fops->release(bdev->bd_disk);
} }
static int blkdev_get_part(struct block_device *part, fmode_t mode) static int blkdev_get_part(struct block_device *part, blk_mode_t mode)
{ {
struct gendisk *disk = part->bd_disk; struct gendisk *disk = part->bd_disk;
int ret; int ret;
if (atomic_read(&part->bd_openers))
goto done;
ret = blkdev_get_whole(bdev_whole(part), mode); ret = blkdev_get_whole(bdev_whole(part), mode);
if (ret) if (ret)
return ret; return ret;
@ -645,26 +693,27 @@ static int blkdev_get_part(struct block_device *part, fmode_t mode)
if (!bdev_nr_sectors(part)) if (!bdev_nr_sectors(part))
goto out_blkdev_put; goto out_blkdev_put;
disk->open_partitions++; if (!atomic_read(&part->bd_openers)) {
set_init_blocksize(part); disk->open_partitions++;
done: set_init_blocksize(part);
}
atomic_inc(&part->bd_openers); atomic_inc(&part->bd_openers);
return 0; return 0;
out_blkdev_put: out_blkdev_put:
blkdev_put_whole(bdev_whole(part), mode); blkdev_put_whole(bdev_whole(part));
return ret; return ret;
} }
static void blkdev_put_part(struct block_device *part, fmode_t mode) static void blkdev_put_part(struct block_device *part)
{ {
struct block_device *whole = bdev_whole(part); struct block_device *whole = bdev_whole(part);
if (!atomic_dec_and_test(&part->bd_openers)) if (atomic_dec_and_test(&part->bd_openers)) {
return; blkdev_flush_mapping(part);
blkdev_flush_mapping(part); whole->bd_disk->open_partitions--;
whole->bd_disk->open_partitions--; }
blkdev_put_whole(whole, mode); blkdev_put_whole(whole);
} }
struct block_device *blkdev_get_no_open(dev_t dev) struct block_device *blkdev_get_no_open(dev_t dev)
@ -699,13 +748,13 @@ void blkdev_put_no_open(struct block_device *bdev)
/** /**
* blkdev_get_by_dev - open a block device by device number * blkdev_get_by_dev - open a block device by device number
* @dev: device number of block device to open * @dev: device number of block device to open
* @mode: FMODE_* mask * @mode: open mode (BLK_OPEN_*)
* @holder: exclusive holder identifier * @holder: exclusive holder identifier
* @hops: holder operations
* *
* Open the block device described by device number @dev. If @mode includes * Open the block device described by device number @dev. If @holder is not
* %FMODE_EXCL, the block device is opened with exclusive access. Specifying * %NULL, the block device is opened with exclusive access. Exclusive opens may
* %FMODE_EXCL with a %NULL @holder is invalid. Exclusive opens may nest for * nest for the same @holder.
* the same @holder.
* *
* Use this interface ONLY if you really do not have anything better - i.e. when * Use this interface ONLY if you really do not have anything better - i.e. when
* you are behind a truly sucky interface and all you are given is a device * you are behind a truly sucky interface and all you are given is a device
@ -717,7 +766,8 @@ void blkdev_put_no_open(struct block_device *bdev)
* RETURNS: * RETURNS:
* Reference to the block_device on success, ERR_PTR(-errno) on failure. * Reference to the block_device on success, ERR_PTR(-errno) on failure.
*/ */
struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder) struct block_device *blkdev_get_by_dev(dev_t dev, blk_mode_t mode, void *holder,
const struct blk_holder_ops *hops)
{ {
bool unblock_events = true; bool unblock_events = true;
struct block_device *bdev; struct block_device *bdev;
@ -726,8 +776,8 @@ struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder)
ret = devcgroup_check_permission(DEVCG_DEV_BLOCK, ret = devcgroup_check_permission(DEVCG_DEV_BLOCK,
MAJOR(dev), MINOR(dev), MAJOR(dev), MINOR(dev),
((mode & FMODE_READ) ? DEVCG_ACC_READ : 0) | ((mode & BLK_OPEN_READ) ? DEVCG_ACC_READ : 0) |
((mode & FMODE_WRITE) ? DEVCG_ACC_WRITE : 0)); ((mode & BLK_OPEN_WRITE) ? DEVCG_ACC_WRITE : 0));
if (ret) if (ret)
return ERR_PTR(ret); return ERR_PTR(ret);
@ -736,10 +786,16 @@ struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder)
return ERR_PTR(-ENXIO); return ERR_PTR(-ENXIO);
disk = bdev->bd_disk; disk = bdev->bd_disk;
if (mode & FMODE_EXCL) { if (holder) {
ret = bd_prepare_to_claim(bdev, holder); mode |= BLK_OPEN_EXCL;
ret = bd_prepare_to_claim(bdev, holder, hops);
if (ret) if (ret)
goto put_blkdev; goto put_blkdev;
} else {
if (WARN_ON_ONCE(mode & BLK_OPEN_EXCL)) {
ret = -EIO;
goto put_blkdev;
}
} }
disk_block_events(disk); disk_block_events(disk);
@ -756,8 +812,8 @@ struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder)
ret = blkdev_get_whole(bdev, mode); ret = blkdev_get_whole(bdev, mode);
if (ret) if (ret)
goto put_module; goto put_module;
if (mode & FMODE_EXCL) { if (holder) {
bd_finish_claiming(bdev, holder); bd_finish_claiming(bdev, holder, hops);
/* /*
* Block event polling for write claims if requested. Any write * Block event polling for write claims if requested. Any write
@ -766,7 +822,7 @@ struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder)
* writeable reference is too fragile given the way @mode is * writeable reference is too fragile given the way @mode is
* used in blkdev_get/put(). * used in blkdev_get/put().
*/ */
if ((mode & FMODE_WRITE) && !bdev->bd_write_holder && if ((mode & BLK_OPEN_WRITE) && !bdev->bd_write_holder &&
(disk->event_flags & DISK_EVENT_FLAG_BLOCK_ON_EXCL_WRITE)) { (disk->event_flags & DISK_EVENT_FLAG_BLOCK_ON_EXCL_WRITE)) {
bdev->bd_write_holder = true; bdev->bd_write_holder = true;
unblock_events = false; unblock_events = false;
@ -780,7 +836,7 @@ struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder)
put_module: put_module:
module_put(disk->fops->owner); module_put(disk->fops->owner);
abort_claiming: abort_claiming:
if (mode & FMODE_EXCL) if (holder)
bd_abort_claiming(bdev, holder); bd_abort_claiming(bdev, holder);
mutex_unlock(&disk->open_mutex); mutex_unlock(&disk->open_mutex);
disk_unblock_events(disk); disk_unblock_events(disk);
@ -793,13 +849,13 @@ EXPORT_SYMBOL(blkdev_get_by_dev);
/** /**
* blkdev_get_by_path - open a block device by name * blkdev_get_by_path - open a block device by name
* @path: path to the block device to open * @path: path to the block device to open
* @mode: FMODE_* mask * @mode: open mode (BLK_OPEN_*)
* @holder: exclusive holder identifier * @holder: exclusive holder identifier
* @hops: holder operations
* *
* Open the block device described by the device file at @path. If @mode * Open the block device described by the device file at @path. If @holder is
* includes %FMODE_EXCL, the block device is opened with exclusive access. * not %NULL, the block device is opened with exclusive access. Exclusive opens
* Specifying %FMODE_EXCL with a %NULL @holder is invalid. Exclusive opens may * may nest for the same @holder.
* nest for the same @holder.
* *
* CONTEXT: * CONTEXT:
* Might sleep. * Might sleep.
@ -807,8 +863,8 @@ EXPORT_SYMBOL(blkdev_get_by_dev);
* RETURNS: * RETURNS:
* Reference to the block_device on success, ERR_PTR(-errno) on failure. * Reference to the block_device on success, ERR_PTR(-errno) on failure.
*/ */
struct block_device *blkdev_get_by_path(const char *path, fmode_t mode, struct block_device *blkdev_get_by_path(const char *path, blk_mode_t mode,
void *holder) void *holder, const struct blk_holder_ops *hops)
{ {
struct block_device *bdev; struct block_device *bdev;
dev_t dev; dev_t dev;
@ -818,9 +874,9 @@ struct block_device *blkdev_get_by_path(const char *path, fmode_t mode,
if (error) if (error)
return ERR_PTR(error); return ERR_PTR(error);
bdev = blkdev_get_by_dev(dev, mode, holder); bdev = blkdev_get_by_dev(dev, mode, holder, hops);
if (!IS_ERR(bdev) && (mode & FMODE_WRITE) && bdev_read_only(bdev)) { if (!IS_ERR(bdev) && (mode & BLK_OPEN_WRITE) && bdev_read_only(bdev)) {
blkdev_put(bdev, mode); blkdev_put(bdev, holder);
return ERR_PTR(-EACCES); return ERR_PTR(-EACCES);
} }
@ -828,7 +884,7 @@ struct block_device *blkdev_get_by_path(const char *path, fmode_t mode,
} }
EXPORT_SYMBOL(blkdev_get_by_path); EXPORT_SYMBOL(blkdev_get_by_path);
void blkdev_put(struct block_device *bdev, fmode_t mode) void blkdev_put(struct block_device *bdev, void *holder)
{ {
struct gendisk *disk = bdev->bd_disk; struct gendisk *disk = bdev->bd_disk;
@ -843,36 +899,8 @@ void blkdev_put(struct block_device *bdev, fmode_t mode)
sync_blockdev(bdev); sync_blockdev(bdev);
mutex_lock(&disk->open_mutex); mutex_lock(&disk->open_mutex);
if (mode & FMODE_EXCL) { if (holder)
struct block_device *whole = bdev_whole(bdev); bd_end_claim(bdev, holder);
bool bdev_free;
/*
* Release a claim on the device. The holder fields
* are protected with bdev_lock. open_mutex is to
* synchronize disk_holder unlinking.
*/
spin_lock(&bdev_lock);
WARN_ON_ONCE(--bdev->bd_holders < 0);
WARN_ON_ONCE(--whole->bd_holders < 0);
if ((bdev_free = !bdev->bd_holders))
bdev->bd_holder = NULL;
if (!whole->bd_holders)
whole->bd_holder = NULL;
spin_unlock(&bdev_lock);
/*
* If this was the last claim, remove holder link and
* unblock evpoll if it was a write holder.
*/
if (bdev_free && bdev->bd_write_holder) {
disk_unblock_events(disk);
bdev->bd_write_holder = false;
}
}
/* /*
* Trigger event checking and tell drivers to flush MEDIA_CHANGE * Trigger event checking and tell drivers to flush MEDIA_CHANGE
@ -882,9 +910,9 @@ void blkdev_put(struct block_device *bdev, fmode_t mode)
disk_flush_events(disk, DISK_EVENT_MEDIA_CHANGE); disk_flush_events(disk, DISK_EVENT_MEDIA_CHANGE);
if (bdev_is_partition(bdev)) if (bdev_is_partition(bdev))
blkdev_put_part(bdev, mode); blkdev_put_part(bdev);
else else
blkdev_put_whole(bdev, mode); blkdev_put_whole(bdev);
mutex_unlock(&disk->open_mutex); mutex_unlock(&disk->open_mutex);
module_put(disk->fops->owner); module_put(disk->fops->owner);

View file

@ -5403,6 +5403,10 @@ void bfq_put_queue(struct bfq_queue *bfqq)
if (bfqq->bfqd->last_completed_rq_bfqq == bfqq) if (bfqq->bfqd->last_completed_rq_bfqq == bfqq)
bfqq->bfqd->last_completed_rq_bfqq = NULL; bfqq->bfqd->last_completed_rq_bfqq = NULL;
WARN_ON_ONCE(!list_empty(&bfqq->fifo));
WARN_ON_ONCE(!RB_EMPTY_ROOT(&bfqq->sort_list));
WARN_ON_ONCE(bfqq->dispatched);
kmem_cache_free(bfq_pool, bfqq); kmem_cache_free(bfq_pool, bfqq);
bfqg_and_blkg_put(bfqg); bfqg_and_blkg_put(bfqg);
} }
@ -7135,6 +7139,7 @@ static void bfq_exit_queue(struct elevator_queue *e)
{ {
struct bfq_data *bfqd = e->elevator_data; struct bfq_data *bfqd = e->elevator_data;
struct bfq_queue *bfqq, *n; struct bfq_queue *bfqq, *n;
unsigned int actuator;
hrtimer_cancel(&bfqd->idle_slice_timer); hrtimer_cancel(&bfqd->idle_slice_timer);
@ -7143,6 +7148,10 @@ static void bfq_exit_queue(struct elevator_queue *e)
bfq_deactivate_bfqq(bfqd, bfqq, false, false); bfq_deactivate_bfqq(bfqd, bfqq, false, false);
spin_unlock_irq(&bfqd->lock); spin_unlock_irq(&bfqd->lock);
for (actuator = 0; actuator < bfqd->num_actuators; actuator++)
WARN_ON_ONCE(bfqd->rq_in_driver[actuator]);
WARN_ON_ONCE(bfqd->tot_rq_in_driver);
hrtimer_cancel(&bfqd->idle_slice_timer); hrtimer_cancel(&bfqd->idle_slice_timer);
/* release oom-queue reference to root group */ /* release oom-queue reference to root group */

View file

@ -1138,6 +1138,14 @@ int bio_add_page(struct bio *bio, struct page *page,
} }
EXPORT_SYMBOL(bio_add_page); EXPORT_SYMBOL(bio_add_page);
void bio_add_folio_nofail(struct bio *bio, struct folio *folio, size_t len,
size_t off)
{
WARN_ON_ONCE(len > UINT_MAX);
WARN_ON_ONCE(off > UINT_MAX);
__bio_add_page(bio, &folio->page, len, off);
}
/** /**
* bio_add_folio - Attempt to add part of a folio to a bio. * bio_add_folio - Attempt to add part of a folio to a bio.
* @bio: BIO to add to. * @bio: BIO to add to.
@ -1169,7 +1177,7 @@ void __bio_release_pages(struct bio *bio, bool mark_dirty)
bio_for_each_segment_all(bvec, bio, iter_all) { bio_for_each_segment_all(bvec, bio, iter_all) {
if (mark_dirty && !PageCompound(bvec->bv_page)) if (mark_dirty && !PageCompound(bvec->bv_page))
set_page_dirty_lock(bvec->bv_page); set_page_dirty_lock(bvec->bv_page);
put_page(bvec->bv_page); bio_release_page(bio, bvec->bv_page);
} }
} }
EXPORT_SYMBOL_GPL(__bio_release_pages); EXPORT_SYMBOL_GPL(__bio_release_pages);
@ -1191,7 +1199,6 @@ void bio_iov_bvec_set(struct bio *bio, struct iov_iter *iter)
bio->bi_io_vec = (struct bio_vec *)iter->bvec; bio->bi_io_vec = (struct bio_vec *)iter->bvec;
bio->bi_iter.bi_bvec_done = iter->iov_offset; bio->bi_iter.bi_bvec_done = iter->iov_offset;
bio->bi_iter.bi_size = size; bio->bi_iter.bi_size = size;
bio_set_flag(bio, BIO_NO_PAGE_REF);
bio_set_flag(bio, BIO_CLONED); bio_set_flag(bio, BIO_CLONED);
} }
@ -1206,7 +1213,7 @@ static int bio_iov_add_page(struct bio *bio, struct page *page,
} }
if (same_page) if (same_page)
put_page(page); bio_release_page(bio, page);
return 0; return 0;
} }
@ -1220,7 +1227,7 @@ static int bio_iov_add_zone_append_page(struct bio *bio, struct page *page,
queue_max_zone_append_sectors(q), &same_page) != len) queue_max_zone_append_sectors(q), &same_page) != len)
return -EINVAL; return -EINVAL;
if (same_page) if (same_page)
put_page(page); bio_release_page(bio, page);
return 0; return 0;
} }
@ -1231,10 +1238,10 @@ static int bio_iov_add_zone_append_page(struct bio *bio, struct page *page,
* @bio: bio to add pages to * @bio: bio to add pages to
* @iter: iov iterator describing the region to be mapped * @iter: iov iterator describing the region to be mapped
* *
* Pins pages from *iter and appends them to @bio's bvec array. The * Extracts pages from *iter and appends them to @bio's bvec array. The pages
* pages will have to be released using put_page() when done. * will have to be cleaned up in the way indicated by the BIO_PAGE_PINNED flag.
* For multi-segment *iter, this function only adds pages from the * For a multi-segment *iter, this function only adds pages from the next
* next non-empty segment of the iov iterator. * non-empty segment of the iov iterator.
*/ */
static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter) static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
{ {
@ -1266,9 +1273,9 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
* result to ensure the bio's total size is correct. The remainder of * result to ensure the bio's total size is correct. The remainder of
* the iov data will be picked up in the next bio iteration. * the iov data will be picked up in the next bio iteration.
*/ */
size = iov_iter_get_pages(iter, pages, size = iov_iter_extract_pages(iter, &pages,
UINT_MAX - bio->bi_iter.bi_size, UINT_MAX - bio->bi_iter.bi_size,
nr_pages, &offset, extraction_flags); nr_pages, extraction_flags, &offset);
if (unlikely(size <= 0)) if (unlikely(size <= 0))
return size ? size : -EFAULT; return size ? size : -EFAULT;
@ -1301,7 +1308,7 @@ static int __bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
iov_iter_revert(iter, left); iov_iter_revert(iter, left);
out: out:
while (i < nr_pages) while (i < nr_pages)
put_page(pages[i++]); bio_release_page(bio, pages[i++]);
return ret; return ret;
} }
@ -1336,6 +1343,8 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter)
return 0; return 0;
} }
if (iov_iter_extract_will_pin(iter))
bio_set_flag(bio, BIO_PAGE_PINNED);
do { do {
ret = __bio_iov_iter_get_pages(bio, iter); ret = __bio_iov_iter_get_pages(bio, iter);
} while (!ret && iov_iter_count(iter) && !bio_full(bio, 0)); } while (!ret && iov_iter_count(iter) && !bio_full(bio, 0));
@ -1489,8 +1498,8 @@ void bio_set_pages_dirty(struct bio *bio)
* the BIO and re-dirty the pages in process context. * the BIO and re-dirty the pages in process context.
* *
* It is expected that bio_check_pages_dirty() will wholly own the BIO from * It is expected that bio_check_pages_dirty() will wholly own the BIO from
* here on. It will run one put_page() against each page and will run one * here on. It will unpin each page and will run one bio_put() against the
* bio_put() against the BIO. * BIO.
*/ */
static void bio_dirty_fn(struct work_struct *work); static void bio_dirty_fn(struct work_struct *work);

View file

@ -34,7 +34,7 @@ int blkcg_set_fc_appid(char *app_id, u64 cgrp_id, size_t app_id_len)
* the vmid from the fabric. * the vmid from the fabric.
* Adding the overhead of a lock is not necessary. * Adding the overhead of a lock is not necessary.
*/ */
strlcpy(blkcg->fc_app_id, app_id, app_id_len); strscpy(blkcg->fc_app_id, app_id, app_id_len);
css_put(css); css_put(css);
out_cgrp_put: out_cgrp_put:
cgroup_put(cgrp); cgroup_put(cgrp);

View file

@ -624,8 +624,13 @@ static int blkcg_reset_stats(struct cgroup_subsys_state *css,
struct blkg_iostat_set *bis = struct blkg_iostat_set *bis =
per_cpu_ptr(blkg->iostat_cpu, cpu); per_cpu_ptr(blkg->iostat_cpu, cpu);
memset(bis, 0, sizeof(*bis)); memset(bis, 0, sizeof(*bis));
/* Re-initialize the cleared blkg_iostat_set */
u64_stats_init(&bis->sync);
bis->blkg = blkg;
} }
memset(&blkg->iostat, 0, sizeof(blkg->iostat)); memset(&blkg->iostat, 0, sizeof(blkg->iostat));
u64_stats_init(&blkg->iostat.sync);
for (i = 0; i < BLKCG_MAX_POLS; i++) { for (i = 0; i < BLKCG_MAX_POLS; i++) {
struct blkcg_policy *pol = blkcg_policy[i]; struct blkcg_policy *pol = blkcg_policy[i];
@ -762,6 +767,13 @@ int blkg_conf_open_bdev(struct blkg_conf_ctx *ctx)
return -ENODEV; return -ENODEV;
} }
mutex_lock(&bdev->bd_queue->rq_qos_mutex);
if (!disk_live(bdev->bd_disk)) {
blkdev_put_no_open(bdev);
mutex_unlock(&bdev->bd_queue->rq_qos_mutex);
return -ENODEV;
}
ctx->body = input; ctx->body = input;
ctx->bdev = bdev; ctx->bdev = bdev;
return 0; return 0;
@ -906,6 +918,7 @@ EXPORT_SYMBOL_GPL(blkg_conf_prep);
*/ */
void blkg_conf_exit(struct blkg_conf_ctx *ctx) void blkg_conf_exit(struct blkg_conf_ctx *ctx)
__releases(&ctx->bdev->bd_queue->queue_lock) __releases(&ctx->bdev->bd_queue->queue_lock)
__releases(&ctx->bdev->bd_queue->rq_qos_mutex)
{ {
if (ctx->blkg) { if (ctx->blkg) {
spin_unlock_irq(&bdev_get_queue(ctx->bdev)->queue_lock); spin_unlock_irq(&bdev_get_queue(ctx->bdev)->queue_lock);
@ -913,6 +926,7 @@ void blkg_conf_exit(struct blkg_conf_ctx *ctx)
} }
if (ctx->bdev) { if (ctx->bdev) {
mutex_unlock(&ctx->bdev->bd_queue->rq_qos_mutex);
blkdev_put_no_open(ctx->bdev); blkdev_put_no_open(ctx->bdev);
ctx->body = NULL; ctx->body = NULL;
ctx->bdev = NULL; ctx->bdev = NULL;

View file

@ -420,6 +420,7 @@ struct request_queue *blk_alloc_queue(int node_id)
mutex_init(&q->debugfs_mutex); mutex_init(&q->debugfs_mutex);
mutex_init(&q->sysfs_lock); mutex_init(&q->sysfs_lock);
mutex_init(&q->sysfs_dir_lock); mutex_init(&q->sysfs_dir_lock);
mutex_init(&q->rq_qos_mutex);
spin_lock_init(&q->queue_lock); spin_lock_init(&q->queue_lock);
init_waitqueue_head(&q->mq_freeze_wq); init_waitqueue_head(&q->mq_freeze_wq);

View file

@ -188,7 +188,9 @@ static void blk_flush_complete_seq(struct request *rq,
case REQ_FSEQ_DATA: case REQ_FSEQ_DATA:
list_move_tail(&rq->flush.list, &fq->flush_data_in_flight); list_move_tail(&rq->flush.list, &fq->flush_data_in_flight);
blk_mq_add_to_requeue_list(rq, BLK_MQ_INSERT_AT_HEAD); spin_lock(&q->requeue_lock);
list_add_tail(&rq->queuelist, &q->flush_list);
spin_unlock(&q->requeue_lock);
blk_mq_kick_requeue_list(q); blk_mq_kick_requeue_list(q);
break; break;
@ -346,7 +348,10 @@ static void blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq,
smp_wmb(); smp_wmb();
req_ref_set(flush_rq, 1); req_ref_set(flush_rq, 1);
blk_mq_add_to_requeue_list(flush_rq, 0); spin_lock(&q->requeue_lock);
list_add_tail(&flush_rq->queuelist, &q->flush_list);
spin_unlock(&q->requeue_lock);
blk_mq_kick_requeue_list(q); blk_mq_kick_requeue_list(q);
} }
@ -376,22 +381,29 @@ static enum rq_end_io_ret mq_flush_data_end_io(struct request *rq,
return RQ_END_IO_NONE; return RQ_END_IO_NONE;
} }
/** static void blk_rq_init_flush(struct request *rq)
* blk_insert_flush - insert a new PREFLUSH/FUA request {
* @rq: request to insert rq->flush.seq = 0;
* INIT_LIST_HEAD(&rq->flush.list);
* To be called from __elv_add_request() for %ELEVATOR_INSERT_FLUSH insertions. rq->rq_flags |= RQF_FLUSH_SEQ;
* or __blk_mq_run_hw_queue() to dispatch request. rq->flush.saved_end_io = rq->end_io; /* Usually NULL */
* @rq is being submitted. Analyze what needs to be done and put it on the rq->end_io = mq_flush_data_end_io;
* right queue. }
/*
* Insert a PREFLUSH/FUA request into the flush state machine.
* Returns true if the request has been consumed by the flush state machine,
* or false if the caller should continue to process it.
*/ */
void blk_insert_flush(struct request *rq) bool blk_insert_flush(struct request *rq)
{ {
struct request_queue *q = rq->q; struct request_queue *q = rq->q;
unsigned long fflags = q->queue_flags; /* may change, cache */ unsigned long fflags = q->queue_flags; /* may change, cache */
unsigned int policy = blk_flush_policy(fflags, rq); unsigned int policy = blk_flush_policy(fflags, rq);
struct blk_flush_queue *fq = blk_get_flush_queue(q, rq->mq_ctx); struct blk_flush_queue *fq = blk_get_flush_queue(q, rq->mq_ctx);
struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
/* FLUSH/FUA request must never be merged */
WARN_ON_ONCE(rq->bio != rq->biotail);
/* /*
* @policy now records what operations need to be done. Adjust * @policy now records what operations need to be done. Adjust
@ -408,45 +420,45 @@ void blk_insert_flush(struct request *rq)
*/ */
rq->cmd_flags |= REQ_SYNC; rq->cmd_flags |= REQ_SYNC;
/* switch (policy) {
* An empty flush handed down from a stacking driver may case 0:
* translate into nothing if the underlying device does not /*
* advertise a write-back cache. In this case, simply * An empty flush handed down from a stacking driver may
* complete the request. * translate into nothing if the underlying device does not
*/ * advertise a write-back cache. In this case, simply
if (!policy) { * complete the request.
*/
blk_mq_end_request(rq, 0); blk_mq_end_request(rq, 0);
return; return true;
case REQ_FSEQ_DATA:
/*
* If there's data, but no flush is necessary, the request can
* be processed directly without going through flush machinery.
* Queue for normal execution.
*/
return false;
case REQ_FSEQ_DATA | REQ_FSEQ_POSTFLUSH:
/*
* Initialize the flush fields and completion handler to trigger
* the post flush, and then just pass the command on.
*/
blk_rq_init_flush(rq);
rq->flush.seq |= REQ_FSEQ_POSTFLUSH;
spin_lock_irq(&fq->mq_flush_lock);
list_move_tail(&rq->flush.list, &fq->flush_data_in_flight);
spin_unlock_irq(&fq->mq_flush_lock);
return false;
default:
/*
* Mark the request as part of a flush sequence and submit it
* for further processing to the flush state machine.
*/
blk_rq_init_flush(rq);
spin_lock_irq(&fq->mq_flush_lock);
blk_flush_complete_seq(rq, fq, REQ_FSEQ_ACTIONS & ~policy, 0);
spin_unlock_irq(&fq->mq_flush_lock);
return true;
} }
BUG_ON(rq->bio != rq->biotail); /*assumes zero or single bio rq */
/*
* If there's data but flush is not necessary, the request can be
* processed directly without going through flush machinery. Queue
* for normal execution.
*/
if ((policy & REQ_FSEQ_DATA) &&
!(policy & (REQ_FSEQ_PREFLUSH | REQ_FSEQ_POSTFLUSH))) {
blk_mq_request_bypass_insert(rq, 0);
blk_mq_run_hw_queue(hctx, false);
return;
}
/*
* @rq should go through flush machinery. Mark it part of flush
* sequence and submit for further processing.
*/
memset(&rq->flush, 0, sizeof(rq->flush));
INIT_LIST_HEAD(&rq->flush.list);
rq->rq_flags |= RQF_FLUSH_SEQ;
rq->flush.saved_end_io = rq->end_io; /* Usually NULL */
rq->end_io = mq_flush_data_end_io;
spin_lock_irq(&fq->mq_flush_lock);
blk_flush_complete_seq(rq, fq, REQ_FSEQ_ACTIONS & ~policy, 0);
spin_unlock_irq(&fq->mq_flush_lock);
} }
/** /**

View file

@ -77,6 +77,10 @@ static void ioc_destroy_icq(struct io_cq *icq)
struct elevator_type *et = q->elevator->type; struct elevator_type *et = q->elevator->type;
lockdep_assert_held(&ioc->lock); lockdep_assert_held(&ioc->lock);
lockdep_assert_held(&q->queue_lock);
if (icq->flags & ICQ_DESTROYED)
return;
radix_tree_delete(&ioc->icq_tree, icq->q->id); radix_tree_delete(&ioc->icq_tree, icq->q->id);
hlist_del_init(&icq->ioc_node); hlist_del_init(&icq->ioc_node);
@ -128,12 +132,7 @@ static void ioc_release_fn(struct work_struct *work)
spin_lock(&q->queue_lock); spin_lock(&q->queue_lock);
spin_lock(&ioc->lock); spin_lock(&ioc->lock);
/* ioc_destroy_icq(icq);
* The icq may have been destroyed when the ioc lock
* was released.
*/
if (!(icq->flags & ICQ_DESTROYED))
ioc_destroy_icq(icq);
spin_unlock(&q->queue_lock); spin_unlock(&q->queue_lock);
rcu_read_unlock(); rcu_read_unlock();
@ -171,23 +170,20 @@ static bool ioc_delay_free(struct io_context *ioc)
*/ */
void ioc_clear_queue(struct request_queue *q) void ioc_clear_queue(struct request_queue *q)
{ {
LIST_HEAD(icq_list);
spin_lock_irq(&q->queue_lock); spin_lock_irq(&q->queue_lock);
list_splice_init(&q->icq_list, &icq_list); while (!list_empty(&q->icq_list)) {
spin_unlock_irq(&q->queue_lock);
rcu_read_lock();
while (!list_empty(&icq_list)) {
struct io_cq *icq = struct io_cq *icq =
list_entry(icq_list.next, struct io_cq, q_node); list_first_entry(&q->icq_list, struct io_cq, q_node);
spin_lock_irq(&icq->ioc->lock); /*
if (!(icq->flags & ICQ_DESTROYED)) * Other context won't hold ioc lock to wait for queue_lock, see
ioc_destroy_icq(icq); * details in ioc_release_fn().
spin_unlock_irq(&icq->ioc->lock); */
spin_lock(&icq->ioc->lock);
ioc_destroy_icq(icq);
spin_unlock(&icq->ioc->lock);
} }
rcu_read_unlock(); spin_unlock_irq(&q->queue_lock);
} }
#else /* CONFIG_BLK_ICQ */ #else /* CONFIG_BLK_ICQ */
static inline void ioc_exit_icqs(struct io_context *ioc) static inline void ioc_exit_icqs(struct io_context *ioc)

View file

@ -2455,6 +2455,7 @@ static u64 adjust_inuse_and_calc_cost(struct ioc_gq *iocg, u64 vtime,
u32 hwi, adj_step; u32 hwi, adj_step;
s64 margin; s64 margin;
u64 cost, new_inuse; u64 cost, new_inuse;
unsigned long flags;
current_hweight(iocg, NULL, &hwi); current_hweight(iocg, NULL, &hwi);
old_hwi = hwi; old_hwi = hwi;
@ -2473,11 +2474,11 @@ static u64 adjust_inuse_and_calc_cost(struct ioc_gq *iocg, u64 vtime,
iocg->inuse == iocg->active) iocg->inuse == iocg->active)
return cost; return cost;
spin_lock_irq(&ioc->lock); spin_lock_irqsave(&ioc->lock, flags);
/* we own inuse only when @iocg is in the normal active state */ /* we own inuse only when @iocg is in the normal active state */
if (iocg->abs_vdebt || list_empty(&iocg->active_list)) { if (iocg->abs_vdebt || list_empty(&iocg->active_list)) {
spin_unlock_irq(&ioc->lock); spin_unlock_irqrestore(&ioc->lock, flags);
return cost; return cost;
} }
@ -2498,7 +2499,7 @@ static u64 adjust_inuse_and_calc_cost(struct ioc_gq *iocg, u64 vtime,
} while (time_after64(vtime + cost, now->vnow) && } while (time_after64(vtime + cost, now->vnow) &&
iocg->inuse != iocg->active); iocg->inuse != iocg->active);
spin_unlock_irq(&ioc->lock); spin_unlock_irqrestore(&ioc->lock, flags);
TRACE_IOCG_PATH(inuse_adjust, iocg, now, TRACE_IOCG_PATH(inuse_adjust, iocg, now,
old_inuse, iocg->inuse, old_hwi, hwi); old_inuse, iocg->inuse, old_hwi, hwi);

View file

@ -23,25 +23,28 @@
/** /**
* enum prio_policy - I/O priority class policy. * enum prio_policy - I/O priority class policy.
* @POLICY_NO_CHANGE: (default) do not modify the I/O priority class. * @POLICY_NO_CHANGE: (default) do not modify the I/O priority class.
* @POLICY_NONE_TO_RT: modify IOPRIO_CLASS_NONE into IOPRIO_CLASS_RT. * @POLICY_PROMOTE_TO_RT: modify no-IOPRIO_CLASS_RT to IOPRIO_CLASS_RT.
* @POLICY_RESTRICT_TO_BE: modify IOPRIO_CLASS_NONE and IOPRIO_CLASS_RT into * @POLICY_RESTRICT_TO_BE: modify IOPRIO_CLASS_NONE and IOPRIO_CLASS_RT into
* IOPRIO_CLASS_BE. * IOPRIO_CLASS_BE.
* @POLICY_ALL_TO_IDLE: change the I/O priority class into IOPRIO_CLASS_IDLE. * @POLICY_ALL_TO_IDLE: change the I/O priority class into IOPRIO_CLASS_IDLE.
* @POLICY_NONE_TO_RT: an alias for POLICY_PROMOTE_TO_RT.
* *
* See also <linux/ioprio.h>. * See also <linux/ioprio.h>.
*/ */
enum prio_policy { enum prio_policy {
POLICY_NO_CHANGE = 0, POLICY_NO_CHANGE = 0,
POLICY_NONE_TO_RT = 1, POLICY_PROMOTE_TO_RT = 1,
POLICY_RESTRICT_TO_BE = 2, POLICY_RESTRICT_TO_BE = 2,
POLICY_ALL_TO_IDLE = 3, POLICY_ALL_TO_IDLE = 3,
POLICY_NONE_TO_RT = 4,
}; };
static const char *policy_name[] = { static const char *policy_name[] = {
[POLICY_NO_CHANGE] = "no-change", [POLICY_NO_CHANGE] = "no-change",
[POLICY_NONE_TO_RT] = "none-to-rt", [POLICY_PROMOTE_TO_RT] = "promote-to-rt",
[POLICY_RESTRICT_TO_BE] = "restrict-to-be", [POLICY_RESTRICT_TO_BE] = "restrict-to-be",
[POLICY_ALL_TO_IDLE] = "idle", [POLICY_ALL_TO_IDLE] = "idle",
[POLICY_NONE_TO_RT] = "none-to-rt",
}; };
static struct blkcg_policy ioprio_policy; static struct blkcg_policy ioprio_policy;
@ -189,6 +192,20 @@ void blkcg_set_ioprio(struct bio *bio)
if (!blkcg || blkcg->prio_policy == POLICY_NO_CHANGE) if (!blkcg || blkcg->prio_policy == POLICY_NO_CHANGE)
return; return;
if (blkcg->prio_policy == POLICY_PROMOTE_TO_RT ||
blkcg->prio_policy == POLICY_NONE_TO_RT) {
/*
* For RT threads, the default priority level is 4 because
* task_nice is 0. By promoting non-RT io-priority to RT-class
* and default level 4, those requests that are already
* RT-class but need a higher io-priority can use ioprio_set()
* to achieve this.
*/
if (IOPRIO_PRIO_CLASS(bio->bi_ioprio) != IOPRIO_CLASS_RT)
bio->bi_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_RT, 4);
return;
}
/* /*
* Except for IOPRIO_CLASS_NONE, higher I/O priority numbers * Except for IOPRIO_CLASS_NONE, higher I/O priority numbers
* correspond to a lower priority. Hence, the max_t() below selects * correspond to a lower priority. Hence, the max_t() below selects

View file

@ -281,21 +281,21 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
if (blk_queue_pci_p2pdma(rq->q)) if (blk_queue_pci_p2pdma(rq->q))
extraction_flags |= ITER_ALLOW_P2PDMA; extraction_flags |= ITER_ALLOW_P2PDMA;
if (iov_iter_extract_will_pin(iter))
bio_set_flag(bio, BIO_PAGE_PINNED);
while (iov_iter_count(iter)) { while (iov_iter_count(iter)) {
struct page **pages, *stack_pages[UIO_FASTIOV]; struct page *stack_pages[UIO_FASTIOV];
struct page **pages = stack_pages;
ssize_t bytes; ssize_t bytes;
size_t offs; size_t offs;
int npages; int npages;
if (nr_vecs <= ARRAY_SIZE(stack_pages)) { if (nr_vecs > ARRAY_SIZE(stack_pages))
pages = stack_pages; pages = NULL;
bytes = iov_iter_get_pages(iter, pages, LONG_MAX,
nr_vecs, &offs, extraction_flags); bytes = iov_iter_extract_pages(iter, &pages, LONG_MAX,
} else { nr_vecs, extraction_flags, &offs);
bytes = iov_iter_get_pages_alloc(iter, &pages,
LONG_MAX, &offs, extraction_flags);
}
if (unlikely(bytes <= 0)) { if (unlikely(bytes <= 0)) {
ret = bytes ? bytes : -EFAULT; ret = bytes ? bytes : -EFAULT;
goto out_unmap; goto out_unmap;
@ -317,7 +317,7 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
if (!bio_add_hw_page(rq->q, bio, page, n, offs, if (!bio_add_hw_page(rq->q, bio, page, n, offs,
max_sectors, &same_page)) { max_sectors, &same_page)) {
if (same_page) if (same_page)
put_page(page); bio_release_page(bio, page);
break; break;
} }
@ -329,7 +329,7 @@ static int bio_map_user_iov(struct request *rq, struct iov_iter *iter,
* release the pages we didn't map into the bio, if any * release the pages we didn't map into the bio, if any
*/ */
while (j < npages) while (j < npages)
put_page(pages[j++]); bio_release_page(bio, pages[j++]);
if (pages != stack_pages) if (pages != stack_pages)
kvfree(pages); kvfree(pages);
/* couldn't stuff something into bio? */ /* couldn't stuff something into bio? */

View file

@ -88,6 +88,7 @@ static const char *const blk_queue_flag_name[] = {
QUEUE_FLAG_NAME(IO_STAT), QUEUE_FLAG_NAME(IO_STAT),
QUEUE_FLAG_NAME(NOXMERGES), QUEUE_FLAG_NAME(NOXMERGES),
QUEUE_FLAG_NAME(ADD_RANDOM), QUEUE_FLAG_NAME(ADD_RANDOM),
QUEUE_FLAG_NAME(SYNCHRONOUS),
QUEUE_FLAG_NAME(SAME_FORCE), QUEUE_FLAG_NAME(SAME_FORCE),
QUEUE_FLAG_NAME(INIT_DONE), QUEUE_FLAG_NAME(INIT_DONE),
QUEUE_FLAG_NAME(STABLE_WRITES), QUEUE_FLAG_NAME(STABLE_WRITES),
@ -103,6 +104,8 @@ static const char *const blk_queue_flag_name[] = {
QUEUE_FLAG_NAME(RQ_ALLOC_TIME), QUEUE_FLAG_NAME(RQ_ALLOC_TIME),
QUEUE_FLAG_NAME(HCTX_ACTIVE), QUEUE_FLAG_NAME(HCTX_ACTIVE),
QUEUE_FLAG_NAME(NOWAIT), QUEUE_FLAG_NAME(NOWAIT),
QUEUE_FLAG_NAME(SQ_SCHED),
QUEUE_FLAG_NAME(SKIP_TAGSET_QUIESCE),
}; };
#undef QUEUE_FLAG_NAME #undef QUEUE_FLAG_NAME
@ -241,14 +244,14 @@ static const char *const cmd_flag_name[] = {
#define RQF_NAME(name) [ilog2((__force u32)RQF_##name)] = #name #define RQF_NAME(name) [ilog2((__force u32)RQF_##name)] = #name
static const char *const rqf_name[] = { static const char *const rqf_name[] = {
RQF_NAME(STARTED), RQF_NAME(STARTED),
RQF_NAME(SOFTBARRIER),
RQF_NAME(FLUSH_SEQ), RQF_NAME(FLUSH_SEQ),
RQF_NAME(MIXED_MERGE), RQF_NAME(MIXED_MERGE),
RQF_NAME(MQ_INFLIGHT), RQF_NAME(MQ_INFLIGHT),
RQF_NAME(DONTPREP), RQF_NAME(DONTPREP),
RQF_NAME(SCHED_TAGS),
RQF_NAME(USE_SCHED),
RQF_NAME(FAILED), RQF_NAME(FAILED),
RQF_NAME(QUIET), RQF_NAME(QUIET),
RQF_NAME(ELVPRIV),
RQF_NAME(IO_STAT), RQF_NAME(IO_STAT),
RQF_NAME(PM), RQF_NAME(PM),
RQF_NAME(HASHED), RQF_NAME(HASHED),
@ -256,7 +259,6 @@ static const char *const rqf_name[] = {
RQF_NAME(SPECIAL_PAYLOAD), RQF_NAME(SPECIAL_PAYLOAD),
RQF_NAME(ZONE_WRITE_LOCKED), RQF_NAME(ZONE_WRITE_LOCKED),
RQF_NAME(TIMED_OUT), RQF_NAME(TIMED_OUT),
RQF_NAME(ELV),
RQF_NAME(RESV), RQF_NAME(RESV),
}; };
#undef RQF_NAME #undef RQF_NAME
@ -399,7 +401,7 @@ static void blk_mq_debugfs_tags_show(struct seq_file *m,
seq_printf(m, "nr_tags=%u\n", tags->nr_tags); seq_printf(m, "nr_tags=%u\n", tags->nr_tags);
seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags); seq_printf(m, "nr_reserved_tags=%u\n", tags->nr_reserved_tags);
seq_printf(m, "active_queues=%d\n", seq_printf(m, "active_queues=%d\n",
atomic_read(&tags->active_queues)); READ_ONCE(tags->active_queues));
seq_puts(m, "\nbitmap_tags:\n"); seq_puts(m, "\nbitmap_tags:\n");
sbitmap_queue_show(&tags->bitmap_tags, m); sbitmap_queue_show(&tags->bitmap_tags, m);

View file

@ -37,7 +37,7 @@ static inline bool
blk_mq_sched_allow_merge(struct request_queue *q, struct request *rq, blk_mq_sched_allow_merge(struct request_queue *q, struct request *rq,
struct bio *bio) struct bio *bio)
{ {
if (rq->rq_flags & RQF_ELV) { if (rq->rq_flags & RQF_USE_SCHED) {
struct elevator_queue *e = q->elevator; struct elevator_queue *e = q->elevator;
if (e->type->ops.allow_merge) if (e->type->ops.allow_merge)
@ -48,7 +48,7 @@ blk_mq_sched_allow_merge(struct request_queue *q, struct request *rq,
static inline void blk_mq_sched_completed_request(struct request *rq, u64 now) static inline void blk_mq_sched_completed_request(struct request *rq, u64 now)
{ {
if (rq->rq_flags & RQF_ELV) { if (rq->rq_flags & RQF_USE_SCHED) {
struct elevator_queue *e = rq->q->elevator; struct elevator_queue *e = rq->q->elevator;
if (e->type->ops.completed_request) if (e->type->ops.completed_request)
@ -58,11 +58,11 @@ static inline void blk_mq_sched_completed_request(struct request *rq, u64 now)
static inline void blk_mq_sched_requeue_request(struct request *rq) static inline void blk_mq_sched_requeue_request(struct request *rq)
{ {
if (rq->rq_flags & RQF_ELV) { if (rq->rq_flags & RQF_USE_SCHED) {
struct request_queue *q = rq->q; struct request_queue *q = rq->q;
struct elevator_queue *e = q->elevator; struct elevator_queue *e = q->elevator;
if ((rq->rq_flags & RQF_ELVPRIV) && e->type->ops.requeue_request) if (e->type->ops.requeue_request)
e->type->ops.requeue_request(rq); e->type->ops.requeue_request(rq);
} }
} }

View file

@ -38,6 +38,7 @@ static void blk_mq_update_wake_batch(struct blk_mq_tags *tags,
void __blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx) void __blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx)
{ {
unsigned int users; unsigned int users;
struct blk_mq_tags *tags = hctx->tags;
/* /*
* calling test_bit() prior to test_and_set_bit() is intentional, * calling test_bit() prior to test_and_set_bit() is intentional,
@ -55,9 +56,11 @@ void __blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx)
return; return;
} }
users = atomic_inc_return(&hctx->tags->active_queues); spin_lock_irq(&tags->lock);
users = tags->active_queues + 1;
blk_mq_update_wake_batch(hctx->tags, users); WRITE_ONCE(tags->active_queues, users);
blk_mq_update_wake_batch(tags, users);
spin_unlock_irq(&tags->lock);
} }
/* /*
@ -90,9 +93,11 @@ void __blk_mq_tag_idle(struct blk_mq_hw_ctx *hctx)
return; return;
} }
users = atomic_dec_return(&tags->active_queues); spin_lock_irq(&tags->lock);
users = tags->active_queues - 1;
WRITE_ONCE(tags->active_queues, users);
blk_mq_update_wake_batch(tags, users); blk_mq_update_wake_batch(tags, users);
spin_unlock_irq(&tags->lock);
blk_mq_tag_wakeup_all(tags, false); blk_mq_tag_wakeup_all(tags, false);
} }

View file

@ -45,6 +45,8 @@
static DEFINE_PER_CPU(struct llist_head, blk_cpu_done); static DEFINE_PER_CPU(struct llist_head, blk_cpu_done);
static void blk_mq_insert_request(struct request *rq, blk_insert_t flags); static void blk_mq_insert_request(struct request *rq, blk_insert_t flags);
static void blk_mq_request_bypass_insert(struct request *rq,
blk_insert_t flags);
static void blk_mq_try_issue_list_directly(struct blk_mq_hw_ctx *hctx, static void blk_mq_try_issue_list_directly(struct blk_mq_hw_ctx *hctx,
struct list_head *list); struct list_head *list);
@ -354,12 +356,12 @@ static struct request *blk_mq_rq_ctx_init(struct blk_mq_alloc_data *data,
data->rq_flags |= RQF_IO_STAT; data->rq_flags |= RQF_IO_STAT;
rq->rq_flags = data->rq_flags; rq->rq_flags = data->rq_flags;
if (!(data->rq_flags & RQF_ELV)) { if (data->rq_flags & RQF_SCHED_TAGS) {
rq->tag = tag;
rq->internal_tag = BLK_MQ_NO_TAG;
} else {
rq->tag = BLK_MQ_NO_TAG; rq->tag = BLK_MQ_NO_TAG;
rq->internal_tag = tag; rq->internal_tag = tag;
} else {
rq->tag = tag;
rq->internal_tag = BLK_MQ_NO_TAG;
} }
rq->timeout = 0; rq->timeout = 0;
@ -386,17 +388,14 @@ static struct request *blk_mq_rq_ctx_init(struct blk_mq_alloc_data *data,
WRITE_ONCE(rq->deadline, 0); WRITE_ONCE(rq->deadline, 0);
req_ref_set(rq, 1); req_ref_set(rq, 1);
if (rq->rq_flags & RQF_ELV) { if (rq->rq_flags & RQF_USE_SCHED) {
struct elevator_queue *e = data->q->elevator; struct elevator_queue *e = data->q->elevator;
INIT_HLIST_NODE(&rq->hash); INIT_HLIST_NODE(&rq->hash);
RB_CLEAR_NODE(&rq->rb_node); RB_CLEAR_NODE(&rq->rb_node);
if (!op_is_flush(data->cmd_flags) && if (e->type->ops.prepare_request)
e->type->ops.prepare_request) {
e->type->ops.prepare_request(rq); e->type->ops.prepare_request(rq);
rq->rq_flags |= RQF_ELVPRIV;
}
} }
return rq; return rq;
@ -449,26 +448,32 @@ static struct request *__blk_mq_alloc_requests(struct blk_mq_alloc_data *data)
data->flags |= BLK_MQ_REQ_NOWAIT; data->flags |= BLK_MQ_REQ_NOWAIT;
if (q->elevator) { if (q->elevator) {
struct elevator_queue *e = q->elevator; /*
* All requests use scheduler tags when an I/O scheduler is
data->rq_flags |= RQF_ELV; * enabled for the queue.
*/
data->rq_flags |= RQF_SCHED_TAGS;
/* /*
* Flush/passthrough requests are special and go directly to the * Flush/passthrough requests are special and go directly to the
* dispatch list. Don't include reserved tags in the * dispatch list.
* limiting, as it isn't useful.
*/ */
if (!op_is_flush(data->cmd_flags) && if ((data->cmd_flags & REQ_OP_MASK) != REQ_OP_FLUSH &&
!blk_op_is_passthrough(data->cmd_flags) && !blk_op_is_passthrough(data->cmd_flags)) {
e->type->ops.limit_depth && struct elevator_mq_ops *ops = &q->elevator->type->ops;
!(data->flags & BLK_MQ_REQ_RESERVED))
e->type->ops.limit_depth(data->cmd_flags, data); WARN_ON_ONCE(data->flags & BLK_MQ_REQ_RESERVED);
data->rq_flags |= RQF_USE_SCHED;
if (ops->limit_depth)
ops->limit_depth(data->cmd_flags, data);
}
} }
retry: retry:
data->ctx = blk_mq_get_ctx(q); data->ctx = blk_mq_get_ctx(q);
data->hctx = blk_mq_map_queue(q, data->cmd_flags, data->ctx); data->hctx = blk_mq_map_queue(q, data->cmd_flags, data->ctx);
if (!(data->rq_flags & RQF_ELV)) if (!(data->rq_flags & RQF_SCHED_TAGS))
blk_mq_tag_busy(data->hctx); blk_mq_tag_busy(data->hctx);
if (data->flags & BLK_MQ_REQ_RESERVED) if (data->flags & BLK_MQ_REQ_RESERVED)
@ -648,10 +653,10 @@ struct request *blk_mq_alloc_request_hctx(struct request_queue *q,
goto out_queue_exit; goto out_queue_exit;
data.ctx = __blk_mq_get_ctx(q, cpu); data.ctx = __blk_mq_get_ctx(q, cpu);
if (!q->elevator) if (q->elevator)
blk_mq_tag_busy(data.hctx); data.rq_flags |= RQF_SCHED_TAGS;
else else
data.rq_flags |= RQF_ELV; blk_mq_tag_busy(data.hctx);
if (flags & BLK_MQ_REQ_RESERVED) if (flags & BLK_MQ_REQ_RESERVED)
data.rq_flags |= RQF_RESV; data.rq_flags |= RQF_RESV;
@ -699,7 +704,7 @@ void blk_mq_free_request(struct request *rq)
{ {
struct request_queue *q = rq->q; struct request_queue *q = rq->q;
if ((rq->rq_flags & RQF_ELVPRIV) && if ((rq->rq_flags & RQF_USE_SCHED) &&
q->elevator->type->ops.finish_request) q->elevator->type->ops.finish_request)
q->elevator->type->ops.finish_request(rq); q->elevator->type->ops.finish_request(rq);
@ -957,6 +962,8 @@ EXPORT_SYMBOL_GPL(blk_update_request);
static inline void blk_account_io_done(struct request *req, u64 now) static inline void blk_account_io_done(struct request *req, u64 now)
{ {
trace_block_io_done(req);
/* /*
* Account IO completion. flush_rq isn't accounted as a * Account IO completion. flush_rq isn't accounted as a
* normal IO on queueing nor completion. Accounting the * normal IO on queueing nor completion. Accounting the
@ -976,6 +983,8 @@ static inline void blk_account_io_done(struct request *req, u64 now)
static inline void blk_account_io_start(struct request *req) static inline void blk_account_io_start(struct request *req)
{ {
trace_block_io_start(req);
if (blk_do_io_stat(req)) { if (blk_do_io_stat(req)) {
/* /*
* All non-passthrough requests are created from a bio with one * All non-passthrough requests are created from a bio with one
@ -1176,8 +1185,9 @@ bool blk_mq_complete_request_remote(struct request *rq)
* or a polled request, always complete locally, * or a polled request, always complete locally,
* it's pointless to redirect the completion. * it's pointless to redirect the completion.
*/ */
if (rq->mq_hctx->nr_ctx == 1 || if ((rq->mq_hctx->nr_ctx == 1 &&
rq->cmd_flags & REQ_POLLED) rq->mq_ctx->cpu == raw_smp_processor_id()) ||
rq->cmd_flags & REQ_POLLED)
return false; return false;
if (blk_mq_complete_need_ipi(rq)) { if (blk_mq_complete_need_ipi(rq)) {
@ -1270,7 +1280,7 @@ static void blk_add_rq_to_plug(struct blk_plug *plug, struct request *rq)
if (!plug->multiple_queues && last && last->q != rq->q) if (!plug->multiple_queues && last && last->q != rq->q)
plug->multiple_queues = true; plug->multiple_queues = true;
if (!plug->has_elevator && (rq->rq_flags & RQF_ELV)) if (!plug->has_elevator && (rq->rq_flags & RQF_USE_SCHED))
plug->has_elevator = true; plug->has_elevator = true;
rq->rq_next = NULL; rq->rq_next = NULL;
rq_list_add(&plug->mq_list, rq); rq_list_add(&plug->mq_list, rq);
@ -1411,13 +1421,16 @@ static void __blk_mq_requeue_request(struct request *rq)
void blk_mq_requeue_request(struct request *rq, bool kick_requeue_list) void blk_mq_requeue_request(struct request *rq, bool kick_requeue_list)
{ {
struct request_queue *q = rq->q; struct request_queue *q = rq->q;
unsigned long flags;
__blk_mq_requeue_request(rq); __blk_mq_requeue_request(rq);
/* this request will be re-inserted to io scheduler queue */ /* this request will be re-inserted to io scheduler queue */
blk_mq_sched_requeue_request(rq); blk_mq_sched_requeue_request(rq);
blk_mq_add_to_requeue_list(rq, BLK_MQ_INSERT_AT_HEAD); spin_lock_irqsave(&q->requeue_lock, flags);
list_add_tail(&rq->queuelist, &q->requeue_list);
spin_unlock_irqrestore(&q->requeue_lock, flags);
if (kick_requeue_list) if (kick_requeue_list)
blk_mq_kick_requeue_list(q); blk_mq_kick_requeue_list(q);
@ -1429,13 +1442,16 @@ static void blk_mq_requeue_work(struct work_struct *work)
struct request_queue *q = struct request_queue *q =
container_of(work, struct request_queue, requeue_work.work); container_of(work, struct request_queue, requeue_work.work);
LIST_HEAD(rq_list); LIST_HEAD(rq_list);
struct request *rq, *next; LIST_HEAD(flush_list);
struct request *rq;
spin_lock_irq(&q->requeue_lock); spin_lock_irq(&q->requeue_lock);
list_splice_init(&q->requeue_list, &rq_list); list_splice_init(&q->requeue_list, &rq_list);
list_splice_init(&q->flush_list, &flush_list);
spin_unlock_irq(&q->requeue_lock); spin_unlock_irq(&q->requeue_lock);
list_for_each_entry_safe(rq, next, &rq_list, queuelist) { while (!list_empty(&rq_list)) {
rq = list_entry(rq_list.next, struct request, queuelist);
/* /*
* If RQF_DONTPREP ist set, the request has been started by the * If RQF_DONTPREP ist set, the request has been started by the
* driver already and might have driver-specific data allocated * driver already and might have driver-specific data allocated
@ -1443,18 +1459,16 @@ static void blk_mq_requeue_work(struct work_struct *work)
* block layer merges for the request. * block layer merges for the request.
*/ */
if (rq->rq_flags & RQF_DONTPREP) { if (rq->rq_flags & RQF_DONTPREP) {
rq->rq_flags &= ~RQF_SOFTBARRIER;
list_del_init(&rq->queuelist); list_del_init(&rq->queuelist);
blk_mq_request_bypass_insert(rq, 0); blk_mq_request_bypass_insert(rq, 0);
} else if (rq->rq_flags & RQF_SOFTBARRIER) { } else {
rq->rq_flags &= ~RQF_SOFTBARRIER;
list_del_init(&rq->queuelist); list_del_init(&rq->queuelist);
blk_mq_insert_request(rq, BLK_MQ_INSERT_AT_HEAD); blk_mq_insert_request(rq, BLK_MQ_INSERT_AT_HEAD);
} }
} }
while (!list_empty(&rq_list)) { while (!list_empty(&flush_list)) {
rq = list_entry(rq_list.next, struct request, queuelist); rq = list_entry(flush_list.next, struct request, queuelist);
list_del_init(&rq->queuelist); list_del_init(&rq->queuelist);
blk_mq_insert_request(rq, 0); blk_mq_insert_request(rq, 0);
} }
@ -1462,27 +1476,6 @@ static void blk_mq_requeue_work(struct work_struct *work)
blk_mq_run_hw_queues(q, false); blk_mq_run_hw_queues(q, false);
} }
void blk_mq_add_to_requeue_list(struct request *rq, blk_insert_t insert_flags)
{
struct request_queue *q = rq->q;
unsigned long flags;
/*
* We abuse this flag that is otherwise used by the I/O scheduler to
* request head insertion from the workqueue.
*/
BUG_ON(rq->rq_flags & RQF_SOFTBARRIER);
spin_lock_irqsave(&q->requeue_lock, flags);
if (insert_flags & BLK_MQ_INSERT_AT_HEAD) {
rq->rq_flags |= RQF_SOFTBARRIER;
list_add(&rq->queuelist, &q->requeue_list);
} else {
list_add_tail(&rq->queuelist, &q->requeue_list);
}
spin_unlock_irqrestore(&q->requeue_lock, flags);
}
void blk_mq_kick_requeue_list(struct request_queue *q) void blk_mq_kick_requeue_list(struct request_queue *q)
{ {
kblockd_mod_delayed_work_on(WORK_CPU_UNBOUND, &q->requeue_work, 0); kblockd_mod_delayed_work_on(WORK_CPU_UNBOUND, &q->requeue_work, 0);
@ -2427,7 +2420,7 @@ static void blk_mq_run_work_fn(struct work_struct *work)
* Should only be used carefully, when the caller knows we want to * Should only be used carefully, when the caller knows we want to
* bypass a potential IO scheduler on the target device. * bypass a potential IO scheduler on the target device.
*/ */
void blk_mq_request_bypass_insert(struct request *rq, blk_insert_t flags) static void blk_mq_request_bypass_insert(struct request *rq, blk_insert_t flags)
{ {
struct blk_mq_hw_ctx *hctx = rq->mq_hctx; struct blk_mq_hw_ctx *hctx = rq->mq_hctx;
@ -2492,7 +2485,7 @@ static void blk_mq_insert_request(struct request *rq, blk_insert_t flags)
* dispatch it given we prioritize requests in hctx->dispatch. * dispatch it given we prioritize requests in hctx->dispatch.
*/ */
blk_mq_request_bypass_insert(rq, flags); blk_mq_request_bypass_insert(rq, flags);
} else if (rq->rq_flags & RQF_FLUSH_SEQ) { } else if (req_op(rq) == REQ_OP_FLUSH) {
/* /*
* Firstly normal IO request is inserted to scheduler queue or * Firstly normal IO request is inserted to scheduler queue or
* sw queue, meantime we add flush request to dispatch queue( * sw queue, meantime we add flush request to dispatch queue(
@ -2622,7 +2615,7 @@ static void blk_mq_try_issue_directly(struct blk_mq_hw_ctx *hctx,
return; return;
} }
if ((rq->rq_flags & RQF_ELV) || !blk_mq_get_budget_and_tag(rq)) { if ((rq->rq_flags & RQF_USE_SCHED) || !blk_mq_get_budget_and_tag(rq)) {
blk_mq_insert_request(rq, 0); blk_mq_insert_request(rq, 0);
blk_mq_run_hw_queue(hctx, false); blk_mq_run_hw_queue(hctx, false);
return; return;
@ -2711,6 +2704,7 @@ static void blk_mq_dispatch_plug_list(struct blk_plug *plug, bool from_sched)
struct request *requeue_list = NULL; struct request *requeue_list = NULL;
struct request **requeue_lastp = &requeue_list; struct request **requeue_lastp = &requeue_list;
unsigned int depth = 0; unsigned int depth = 0;
bool is_passthrough = false;
LIST_HEAD(list); LIST_HEAD(list);
do { do {
@ -2719,7 +2713,9 @@ static void blk_mq_dispatch_plug_list(struct blk_plug *plug, bool from_sched)
if (!this_hctx) { if (!this_hctx) {
this_hctx = rq->mq_hctx; this_hctx = rq->mq_hctx;
this_ctx = rq->mq_ctx; this_ctx = rq->mq_ctx;
} else if (this_hctx != rq->mq_hctx || this_ctx != rq->mq_ctx) { is_passthrough = blk_rq_is_passthrough(rq);
} else if (this_hctx != rq->mq_hctx || this_ctx != rq->mq_ctx ||
is_passthrough != blk_rq_is_passthrough(rq)) {
rq_list_add_tail(&requeue_lastp, rq); rq_list_add_tail(&requeue_lastp, rq);
continue; continue;
} }
@ -2731,7 +2727,13 @@ static void blk_mq_dispatch_plug_list(struct blk_plug *plug, bool from_sched)
trace_block_unplug(this_hctx->queue, depth, !from_sched); trace_block_unplug(this_hctx->queue, depth, !from_sched);
percpu_ref_get(&this_hctx->queue->q_usage_counter); percpu_ref_get(&this_hctx->queue->q_usage_counter);
if (this_hctx->queue->elevator) { /* passthrough requests should never be issued to the I/O scheduler */
if (is_passthrough) {
spin_lock(&this_hctx->lock);
list_splice_tail_init(&list, &this_hctx->dispatch);
spin_unlock(&this_hctx->lock);
blk_mq_run_hw_queue(this_hctx, from_sched);
} else if (this_hctx->queue->elevator) {
this_hctx->queue->elevator->type->ops.insert_requests(this_hctx, this_hctx->queue->elevator->type->ops.insert_requests(this_hctx,
&list, 0); &list, 0);
blk_mq_run_hw_queue(this_hctx, from_sched); blk_mq_run_hw_queue(this_hctx, from_sched);
@ -2970,10 +2972,8 @@ void blk_mq_submit_bio(struct bio *bio)
return; return;
} }
if (op_is_flush(bio->bi_opf)) { if (op_is_flush(bio->bi_opf) && blk_insert_flush(rq))
blk_insert_flush(rq);
return; return;
}
if (plug) { if (plug) {
blk_add_rq_to_plug(plug, rq); blk_add_rq_to_plug(plug, rq);
@ -2981,7 +2981,7 @@ void blk_mq_submit_bio(struct bio *bio)
} }
hctx = rq->mq_hctx; hctx = rq->mq_hctx;
if ((rq->rq_flags & RQF_ELV) || if ((rq->rq_flags & RQF_USE_SCHED) ||
(hctx->dispatch_busy && (q->nr_hw_queues == 1 || !is_sync))) { (hctx->dispatch_busy && (q->nr_hw_queues == 1 || !is_sync))) {
blk_mq_insert_request(rq, 0); blk_mq_insert_request(rq, 0);
blk_mq_run_hw_queue(hctx, true); blk_mq_run_hw_queue(hctx, true);
@ -4232,6 +4232,7 @@ int blk_mq_init_allocated_queue(struct blk_mq_tag_set *set,
blk_mq_update_poll_flag(q); blk_mq_update_poll_flag(q);
INIT_DELAYED_WORK(&q->requeue_work, blk_mq_requeue_work); INIT_DELAYED_WORK(&q->requeue_work, blk_mq_requeue_work);
INIT_LIST_HEAD(&q->flush_list);
INIT_LIST_HEAD(&q->requeue_list); INIT_LIST_HEAD(&q->requeue_list);
spin_lock_init(&q->requeue_lock); spin_lock_init(&q->requeue_lock);
@ -4608,9 +4609,6 @@ static bool blk_mq_elv_switch_none(struct list_head *head,
{ {
struct blk_mq_qe_pair *qe; struct blk_mq_qe_pair *qe;
if (!q->elevator)
return true;
qe = kmalloc(sizeof(*qe), GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY); qe = kmalloc(sizeof(*qe), GFP_NOIO | __GFP_NOWARN | __GFP_NORETRY);
if (!qe) if (!qe)
return false; return false;
@ -4618,6 +4616,12 @@ static bool blk_mq_elv_switch_none(struct list_head *head,
/* q->elevator needs protection from ->sysfs_lock */ /* q->elevator needs protection from ->sysfs_lock */
mutex_lock(&q->sysfs_lock); mutex_lock(&q->sysfs_lock);
/* the check has to be done with holding sysfs_lock */
if (!q->elevator) {
kfree(qe);
goto unlock;
}
INIT_LIST_HEAD(&qe->node); INIT_LIST_HEAD(&qe->node);
qe->q = q; qe->q = q;
qe->type = q->elevator->type; qe->type = q->elevator->type;
@ -4625,6 +4629,7 @@ static bool blk_mq_elv_switch_none(struct list_head *head,
__elevator_get(qe->type); __elevator_get(qe->type);
list_add(&qe->node, head); list_add(&qe->node, head);
elevator_disable(q); elevator_disable(q);
unlock:
mutex_unlock(&q->sysfs_lock); mutex_unlock(&q->sysfs_lock);
return true; return true;

View file

@ -47,7 +47,6 @@ int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr);
void blk_mq_wake_waiters(struct request_queue *q); void blk_mq_wake_waiters(struct request_queue *q);
bool blk_mq_dispatch_rq_list(struct blk_mq_hw_ctx *hctx, struct list_head *, bool blk_mq_dispatch_rq_list(struct blk_mq_hw_ctx *hctx, struct list_head *,
unsigned int); unsigned int);
void blk_mq_add_to_requeue_list(struct request *rq, blk_insert_t insert_flags);
void blk_mq_flush_busy_ctxs(struct blk_mq_hw_ctx *hctx, struct list_head *list); void blk_mq_flush_busy_ctxs(struct blk_mq_hw_ctx *hctx, struct list_head *list);
struct request *blk_mq_dequeue_from_ctx(struct blk_mq_hw_ctx *hctx, struct request *blk_mq_dequeue_from_ctx(struct blk_mq_hw_ctx *hctx,
struct blk_mq_ctx *start); struct blk_mq_ctx *start);
@ -64,10 +63,6 @@ struct blk_mq_tags *blk_mq_alloc_map_and_rqs(struct blk_mq_tag_set *set,
void blk_mq_free_map_and_rqs(struct blk_mq_tag_set *set, void blk_mq_free_map_and_rqs(struct blk_mq_tag_set *set,
struct blk_mq_tags *tags, struct blk_mq_tags *tags,
unsigned int hctx_idx); unsigned int hctx_idx);
/*
* Internal helpers for request insertion into sw queues
*/
void blk_mq_request_bypass_insert(struct request *rq, blk_insert_t flags);
/* /*
* CPU -> queue mappings * CPU -> queue mappings
@ -226,9 +221,9 @@ static inline bool blk_mq_is_shared_tags(unsigned int flags)
static inline struct blk_mq_tags *blk_mq_tags_from_data(struct blk_mq_alloc_data *data) static inline struct blk_mq_tags *blk_mq_tags_from_data(struct blk_mq_alloc_data *data)
{ {
if (!(data->rq_flags & RQF_ELV)) if (data->rq_flags & RQF_SCHED_TAGS)
return data->hctx->tags; return data->hctx->sched_tags;
return data->hctx->sched_tags; return data->hctx->tags;
} }
static inline bool blk_mq_hctx_stopped(struct blk_mq_hw_ctx *hctx) static inline bool blk_mq_hctx_stopped(struct blk_mq_hw_ctx *hctx)
@ -417,8 +412,7 @@ static inline bool hctx_may_queue(struct blk_mq_hw_ctx *hctx,
return true; return true;
} }
users = atomic_read(&hctx->tags->active_queues); users = READ_ONCE(hctx->tags->active_queues);
if (!users) if (!users)
return true; return true;

View file

@ -288,11 +288,13 @@ void rq_qos_wait(struct rq_wait *rqw, void *private_data,
void rq_qos_exit(struct request_queue *q) void rq_qos_exit(struct request_queue *q)
{ {
mutex_lock(&q->rq_qos_mutex);
while (q->rq_qos) { while (q->rq_qos) {
struct rq_qos *rqos = q->rq_qos; struct rq_qos *rqos = q->rq_qos;
q->rq_qos = rqos->next; q->rq_qos = rqos->next;
rqos->ops->exit(rqos); rqos->ops->exit(rqos);
} }
mutex_unlock(&q->rq_qos_mutex);
} }
int rq_qos_add(struct rq_qos *rqos, struct gendisk *disk, enum rq_qos_id id, int rq_qos_add(struct rq_qos *rqos, struct gendisk *disk, enum rq_qos_id id,
@ -300,6 +302,8 @@ int rq_qos_add(struct rq_qos *rqos, struct gendisk *disk, enum rq_qos_id id,
{ {
struct request_queue *q = disk->queue; struct request_queue *q = disk->queue;
lockdep_assert_held(&q->rq_qos_mutex);
rqos->disk = disk; rqos->disk = disk;
rqos->id = id; rqos->id = id;
rqos->ops = ops; rqos->ops = ops;
@ -307,18 +311,13 @@ int rq_qos_add(struct rq_qos *rqos, struct gendisk *disk, enum rq_qos_id id,
/* /*
* No IO can be in-flight when adding rqos, so freeze queue, which * No IO can be in-flight when adding rqos, so freeze queue, which
* is fine since we only support rq_qos for blk-mq queue. * is fine since we only support rq_qos for blk-mq queue.
*
* Reuse ->queue_lock for protecting against other concurrent
* rq_qos adding/deleting
*/ */
blk_mq_freeze_queue(q); blk_mq_freeze_queue(q);
spin_lock_irq(&q->queue_lock);
if (rq_qos_id(q, rqos->id)) if (rq_qos_id(q, rqos->id))
goto ebusy; goto ebusy;
rqos->next = q->rq_qos; rqos->next = q->rq_qos;
q->rq_qos = rqos; q->rq_qos = rqos;
spin_unlock_irq(&q->queue_lock);
blk_mq_unfreeze_queue(q); blk_mq_unfreeze_queue(q);
@ -330,7 +329,6 @@ int rq_qos_add(struct rq_qos *rqos, struct gendisk *disk, enum rq_qos_id id,
return 0; return 0;
ebusy: ebusy:
spin_unlock_irq(&q->queue_lock);
blk_mq_unfreeze_queue(q); blk_mq_unfreeze_queue(q);
return -EBUSY; return -EBUSY;
} }
@ -340,21 +338,15 @@ void rq_qos_del(struct rq_qos *rqos)
struct request_queue *q = rqos->disk->queue; struct request_queue *q = rqos->disk->queue;
struct rq_qos **cur; struct rq_qos **cur;
/* lockdep_assert_held(&q->rq_qos_mutex);
* See comment in rq_qos_add() about freezing queue & using
* ->queue_lock.
*/
blk_mq_freeze_queue(q);
spin_lock_irq(&q->queue_lock); blk_mq_freeze_queue(q);
for (cur = &q->rq_qos; *cur; cur = &(*cur)->next) { for (cur = &q->rq_qos; *cur; cur = &(*cur)->next) {
if (*cur == rqos) { if (*cur == rqos) {
*cur = rqos->next; *cur = rqos->next;
break; break;
} }
} }
spin_unlock_irq(&q->queue_lock);
blk_mq_unfreeze_queue(q); blk_mq_unfreeze_queue(q);
mutex_lock(&q->debugfs_mutex); mutex_lock(&q->debugfs_mutex);

View file

@ -944,7 +944,9 @@ int wbt_init(struct gendisk *disk)
/* /*
* Assign rwb and add the stats callback. * Assign rwb and add the stats callback.
*/ */
mutex_lock(&q->rq_qos_mutex);
ret = rq_qos_add(&rwb->rqos, disk, RQ_QOS_WBT, &wbt_rqos_ops); ret = rq_qos_add(&rwb->rqos, disk, RQ_QOS_WBT, &wbt_rqos_ops);
mutex_unlock(&q->rq_qos_mutex);
if (ret) if (ret)
goto err_free; goto err_free;

View file

@ -57,16 +57,10 @@ EXPORT_SYMBOL_GPL(blk_zone_cond_str);
*/ */
bool blk_req_needs_zone_write_lock(struct request *rq) bool blk_req_needs_zone_write_lock(struct request *rq)
{ {
if (blk_rq_is_passthrough(rq))
return false;
if (!rq->q->disk->seq_zones_wlock) if (!rq->q->disk->seq_zones_wlock)
return false; return false;
if (bdev_op_is_zoned_write(rq->q->disk->part0, req_op(rq))) return blk_rq_is_seq_zoned_write(rq);
return blk_rq_zone_is_seq(rq);
return false;
} }
EXPORT_SYMBOL_GPL(blk_req_needs_zone_write_lock); EXPORT_SYMBOL_GPL(blk_req_needs_zone_write_lock);
@ -329,8 +323,8 @@ static int blkdev_copy_zone_to_user(struct blk_zone *zone, unsigned int idx,
* BLKREPORTZONE ioctl processing. * BLKREPORTZONE ioctl processing.
* Called from blkdev_ioctl. * Called from blkdev_ioctl.
*/ */
int blkdev_report_zones_ioctl(struct block_device *bdev, fmode_t mode, int blkdev_report_zones_ioctl(struct block_device *bdev, unsigned int cmd,
unsigned int cmd, unsigned long arg) unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
struct zone_report_args args; struct zone_report_args args;
@ -362,8 +356,8 @@ int blkdev_report_zones_ioctl(struct block_device *bdev, fmode_t mode,
return 0; return 0;
} }
static int blkdev_truncate_zone_range(struct block_device *bdev, fmode_t mode, static int blkdev_truncate_zone_range(struct block_device *bdev,
const struct blk_zone_range *zrange) blk_mode_t mode, const struct blk_zone_range *zrange)
{ {
loff_t start, end; loff_t start, end;
@ -382,7 +376,7 @@ static int blkdev_truncate_zone_range(struct block_device *bdev, fmode_t mode,
* BLKRESETZONE, BLKOPENZONE, BLKCLOSEZONE and BLKFINISHZONE ioctl processing. * BLKRESETZONE, BLKOPENZONE, BLKCLOSEZONE and BLKFINISHZONE ioctl processing.
* Called from blkdev_ioctl. * Called from blkdev_ioctl.
*/ */
int blkdev_zone_mgmt_ioctl(struct block_device *bdev, fmode_t mode, int blkdev_zone_mgmt_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
@ -396,7 +390,7 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, fmode_t mode,
if (!bdev_is_zoned(bdev)) if (!bdev_is_zoned(bdev))
return -ENOTTY; return -ENOTTY;
if (!(mode & FMODE_WRITE)) if (!(mode & BLK_OPEN_WRITE))
return -EBADF; return -EBADF;
if (copy_from_user(&zrange, argp, sizeof(struct blk_zone_range))) if (copy_from_user(&zrange, argp, sizeof(struct blk_zone_range)))

View file

@ -269,7 +269,7 @@ bool blk_bio_list_merge(struct request_queue *q, struct list_head *list,
*/ */
#define ELV_ON_HASH(rq) ((rq)->rq_flags & RQF_HASHED) #define ELV_ON_HASH(rq) ((rq)->rq_flags & RQF_HASHED)
void blk_insert_flush(struct request *rq); bool blk_insert_flush(struct request *rq);
int elevator_switch(struct request_queue *q, struct elevator_type *new_e); int elevator_switch(struct request_queue *q, struct elevator_type *new_e);
void elevator_disable(struct request_queue *q); void elevator_disable(struct request_queue *q);
@ -394,10 +394,27 @@ static inline struct bio *blk_queue_bounce(struct bio *bio,
#ifdef CONFIG_BLK_DEV_ZONED #ifdef CONFIG_BLK_DEV_ZONED
void disk_free_zone_bitmaps(struct gendisk *disk); void disk_free_zone_bitmaps(struct gendisk *disk);
void disk_clear_zone_settings(struct gendisk *disk); void disk_clear_zone_settings(struct gendisk *disk);
#else int blkdev_report_zones_ioctl(struct block_device *bdev, unsigned int cmd,
unsigned long arg);
int blkdev_zone_mgmt_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long arg);
#else /* CONFIG_BLK_DEV_ZONED */
static inline void disk_free_zone_bitmaps(struct gendisk *disk) {} static inline void disk_free_zone_bitmaps(struct gendisk *disk) {}
static inline void disk_clear_zone_settings(struct gendisk *disk) {} static inline void disk_clear_zone_settings(struct gendisk *disk) {}
#endif static inline int blkdev_report_zones_ioctl(struct block_device *bdev,
unsigned int cmd, unsigned long arg)
{
return -ENOTTY;
}
static inline int blkdev_zone_mgmt_ioctl(struct block_device *bdev,
blk_mode_t mode, unsigned int cmd, unsigned long arg)
{
return -ENOTTY;
}
#endif /* CONFIG_BLK_DEV_ZONED */
struct block_device *bdev_alloc(struct gendisk *disk, u8 partno);
void bdev_add(struct block_device *bdev, dev_t dev);
int blk_alloc_ext_minor(void); int blk_alloc_ext_minor(void);
void blk_free_ext_minor(unsigned int minor); void blk_free_ext_minor(unsigned int minor);
@ -409,7 +426,7 @@ int bdev_add_partition(struct gendisk *disk, int partno, sector_t start,
int bdev_del_partition(struct gendisk *disk, int partno); int bdev_del_partition(struct gendisk *disk, int partno);
int bdev_resize_partition(struct gendisk *disk, int partno, sector_t start, int bdev_resize_partition(struct gendisk *disk, int partno, sector_t start,
sector_t length); sector_t length);
void blk_drop_partitions(struct gendisk *disk); void drop_partition(struct block_device *part);
void bdev_set_nr_sectors(struct block_device *bdev, sector_t sectors); void bdev_set_nr_sectors(struct block_device *bdev, sector_t sectors);
@ -420,9 +437,19 @@ int bio_add_hw_page(struct request_queue *q, struct bio *bio,
struct page *page, unsigned int len, unsigned int offset, struct page *page, unsigned int len, unsigned int offset,
unsigned int max_sectors, bool *same_page); unsigned int max_sectors, bool *same_page);
/*
* Clean up a page appropriately, where the page may be pinned, may have a
* ref taken on it or neither.
*/
static inline void bio_release_page(struct bio *bio, struct page *page)
{
if (bio_flagged(bio, BIO_PAGE_PINNED))
unpin_user_page(page);
}
struct request_queue *blk_alloc_queue(int node_id); struct request_queue *blk_alloc_queue(int node_id);
int disk_scan_partitions(struct gendisk *disk, fmode_t mode); int disk_scan_partitions(struct gendisk *disk, blk_mode_t mode);
int disk_alloc_events(struct gendisk *disk); int disk_alloc_events(struct gendisk *disk);
void disk_add_events(struct gendisk *disk); void disk_add_events(struct gendisk *disk);
@ -437,6 +464,9 @@ extern struct device_attribute dev_attr_events_poll_msecs;
extern struct attribute_group blk_trace_attr_group; extern struct attribute_group blk_trace_attr_group;
blk_mode_t file_to_blk_mode(struct file *file);
int truncate_bdev_range(struct block_device *bdev, blk_mode_t mode,
loff_t lstart, loff_t lend);
long blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg); long blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg);
long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg); long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg);

View file

@ -26,7 +26,7 @@ struct bsg_set {
}; };
static int bsg_transport_sg_io_fn(struct request_queue *q, struct sg_io_v4 *hdr, static int bsg_transport_sg_io_fn(struct request_queue *q, struct sg_io_v4 *hdr,
fmode_t mode, unsigned int timeout) bool open_for_write, unsigned int timeout)
{ {
struct bsg_job *job; struct bsg_job *job;
struct request *rq; struct request *rq;

View file

@ -39,7 +39,7 @@ static inline struct bsg_device *to_bsg_device(struct inode *inode)
#define BSG_MAX_DEVS 32768 #define BSG_MAX_DEVS 32768
static DEFINE_IDA(bsg_minor_ida); static DEFINE_IDA(bsg_minor_ida);
static struct class *bsg_class; static const struct class bsg_class;
static int bsg_major; static int bsg_major;
static unsigned int bsg_timeout(struct bsg_device *bd, struct sg_io_v4 *hdr) static unsigned int bsg_timeout(struct bsg_device *bd, struct sg_io_v4 *hdr)
@ -54,7 +54,8 @@ static unsigned int bsg_timeout(struct bsg_device *bd, struct sg_io_v4 *hdr)
return max_t(unsigned int, timeout, BLK_MIN_SG_TIMEOUT); return max_t(unsigned int, timeout, BLK_MIN_SG_TIMEOUT);
} }
static int bsg_sg_io(struct bsg_device *bd, fmode_t mode, void __user *uarg) static int bsg_sg_io(struct bsg_device *bd, bool open_for_write,
void __user *uarg)
{ {
struct sg_io_v4 hdr; struct sg_io_v4 hdr;
int ret; int ret;
@ -63,7 +64,8 @@ static int bsg_sg_io(struct bsg_device *bd, fmode_t mode, void __user *uarg)
return -EFAULT; return -EFAULT;
if (hdr.guard != 'Q') if (hdr.guard != 'Q')
return -EINVAL; return -EINVAL;
ret = bd->sg_io_fn(bd->queue, &hdr, mode, bsg_timeout(bd, &hdr)); ret = bd->sg_io_fn(bd->queue, &hdr, open_for_write,
bsg_timeout(bd, &hdr));
if (!ret && copy_to_user(uarg, &hdr, sizeof(hdr))) if (!ret && copy_to_user(uarg, &hdr, sizeof(hdr)))
return -EFAULT; return -EFAULT;
return ret; return ret;
@ -146,7 +148,7 @@ static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case SG_EMULATED_HOST: case SG_EMULATED_HOST:
return put_user(1, intp); return put_user(1, intp);
case SG_IO: case SG_IO:
return bsg_sg_io(bd, file->f_mode, uarg); return bsg_sg_io(bd, file->f_mode & FMODE_WRITE, uarg);
case SCSI_IOCTL_SEND_COMMAND: case SCSI_IOCTL_SEND_COMMAND:
pr_warn_ratelimited("%s: calling unsupported SCSI_IOCTL_SEND_COMMAND\n", pr_warn_ratelimited("%s: calling unsupported SCSI_IOCTL_SEND_COMMAND\n",
current->comm); current->comm);
@ -206,7 +208,7 @@ struct bsg_device *bsg_register_queue(struct request_queue *q,
return ERR_PTR(ret); return ERR_PTR(ret);
} }
bd->device.devt = MKDEV(bsg_major, ret); bd->device.devt = MKDEV(bsg_major, ret);
bd->device.class = bsg_class; bd->device.class = &bsg_class;
bd->device.parent = parent; bd->device.parent = parent;
bd->device.release = bsg_device_release; bd->device.release = bsg_device_release;
dev_set_name(&bd->device, "%s", name); dev_set_name(&bd->device, "%s", name);
@ -240,15 +242,19 @@ static char *bsg_devnode(const struct device *dev, umode_t *mode)
return kasprintf(GFP_KERNEL, "bsg/%s", dev_name(dev)); return kasprintf(GFP_KERNEL, "bsg/%s", dev_name(dev));
} }
static const struct class bsg_class = {
.name = "bsg",
.devnode = bsg_devnode,
};
static int __init bsg_init(void) static int __init bsg_init(void)
{ {
dev_t devid; dev_t devid;
int ret; int ret;
bsg_class = class_create("bsg"); ret = class_register(&bsg_class);
if (IS_ERR(bsg_class)) if (ret)
return PTR_ERR(bsg_class); return ret;
bsg_class->devnode = bsg_devnode;
ret = alloc_chrdev_region(&devid, 0, BSG_MAX_DEVS, "bsg"); ret = alloc_chrdev_region(&devid, 0, BSG_MAX_DEVS, "bsg");
if (ret) if (ret)
@ -260,7 +266,7 @@ static int __init bsg_init(void)
return 0; return 0;
destroy_bsg_class: destroy_bsg_class:
class_destroy(bsg_class); class_unregister(&bsg_class);
return ret; return ret;
} }

View file

@ -263,31 +263,31 @@ static unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask)
} }
/** /**
* bdev_check_media_change - check if a removable media has been changed * disk_check_media_change - check if a removable media has been changed
* @bdev: block device to check * @disk: gendisk to check
* *
* Check whether a removable media has been changed, and attempt to free all * Check whether a removable media has been changed, and attempt to free all
* dentries and inodes and invalidates all block device page cache entries in * dentries and inodes and invalidates all block device page cache entries in
* that case. * that case.
* *
* Returns %true if the block device changed, or %false if not. * Returns %true if the media has changed, or %false if not.
*/ */
bool bdev_check_media_change(struct block_device *bdev) bool disk_check_media_change(struct gendisk *disk)
{ {
unsigned int events; unsigned int events;
events = disk_clear_events(bdev->bd_disk, DISK_EVENT_MEDIA_CHANGE | events = disk_clear_events(disk, DISK_EVENT_MEDIA_CHANGE |
DISK_EVENT_EJECT_REQUEST); DISK_EVENT_EJECT_REQUEST);
if (!(events & DISK_EVENT_MEDIA_CHANGE)) if (!(events & DISK_EVENT_MEDIA_CHANGE))
return false; return false;
if (__invalidate_device(bdev, true)) if (__invalidate_device(disk->part0, true))
pr_warn("VFS: busy inodes on changed media %s\n", pr_warn("VFS: busy inodes on changed media %s\n",
bdev->bd_disk->disk_name); disk->disk_name);
set_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state); set_bit(GD_NEED_PART_SCAN, &disk->state);
return true; return true;
} }
EXPORT_SYMBOL(bdev_check_media_change); EXPORT_SYMBOL(disk_check_media_change);
/** /**
* disk_force_media_change - force a media change event * disk_force_media_change - force a media change event
@ -307,6 +307,7 @@ bool disk_force_media_change(struct gendisk *disk, unsigned int events)
if (!(events & DISK_EVENT_MEDIA_CHANGE)) if (!(events & DISK_EVENT_MEDIA_CHANGE))
return false; return false;
inc_diskseq(disk);
if (__invalidate_device(disk->part0, true)) if (__invalidate_device(disk->part0, true))
pr_warn("VFS: busy inodes on changed media %s\n", pr_warn("VFS: busy inodes on changed media %s\n",
disk->disk_name); disk->disk_name);

316
block/early-lookup.c Normal file
View file

@ -0,0 +1,316 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Code for looking up block devices in the early boot code before mounting the
* root file system.
*/
#include <linux/blkdev.h>
#include <linux/ctype.h>
struct uuidcmp {
const char *uuid;
int len;
};
/**
* match_dev_by_uuid - callback for finding a partition using its uuid
* @dev: device passed in by the caller
* @data: opaque pointer to the desired struct uuidcmp to match
*
* Returns 1 if the device matches, and 0 otherwise.
*/
static int __init match_dev_by_uuid(struct device *dev, const void *data)
{
struct block_device *bdev = dev_to_bdev(dev);
const struct uuidcmp *cmp = data;
if (!bdev->bd_meta_info ||
strncasecmp(cmp->uuid, bdev->bd_meta_info->uuid, cmp->len))
return 0;
return 1;
}
/**
* devt_from_partuuid - looks up the dev_t of a partition by its UUID
* @uuid_str: char array containing ascii UUID
* @devt: dev_t result
*
* The function will return the first partition which contains a matching
* UUID value in its partition_meta_info struct. This does not search
* by filesystem UUIDs.
*
* If @uuid_str is followed by a "/PARTNROFF=%d", then the number will be
* extracted and used as an offset from the partition identified by the UUID.
*
* Returns 0 on success or a negative error code on failure.
*/
static int __init devt_from_partuuid(const char *uuid_str, dev_t *devt)
{
struct uuidcmp cmp;
struct device *dev = NULL;
int offset = 0;
char *slash;
cmp.uuid = uuid_str;
slash = strchr(uuid_str, '/');
/* Check for optional partition number offset attributes. */
if (slash) {
char c = 0;
/* Explicitly fail on poor PARTUUID syntax. */
if (sscanf(slash + 1, "PARTNROFF=%d%c", &offset, &c) != 1)
goto out_invalid;
cmp.len = slash - uuid_str;
} else {
cmp.len = strlen(uuid_str);
}
if (!cmp.len)
goto out_invalid;
dev = class_find_device(&block_class, NULL, &cmp, &match_dev_by_uuid);
if (!dev)
return -ENODEV;
if (offset) {
/*
* Attempt to find the requested partition by adding an offset
* to the partition number found by UUID.
*/
*devt = part_devt(dev_to_disk(dev),
dev_to_bdev(dev)->bd_partno + offset);
} else {
*devt = dev->devt;
}
put_device(dev);
return 0;
out_invalid:
pr_err("VFS: PARTUUID= is invalid.\n"
"Expected PARTUUID=<valid-uuid-id>[/PARTNROFF=%%d]\n");
return -EINVAL;
}
/**
* match_dev_by_label - callback for finding a partition using its label
* @dev: device passed in by the caller
* @data: opaque pointer to the label to match
*
* Returns 1 if the device matches, and 0 otherwise.
*/
static int __init match_dev_by_label(struct device *dev, const void *data)
{
struct block_device *bdev = dev_to_bdev(dev);
const char *label = data;
if (!bdev->bd_meta_info || strcmp(label, bdev->bd_meta_info->volname))
return 0;
return 1;
}
static int __init devt_from_partlabel(const char *label, dev_t *devt)
{
struct device *dev;
dev = class_find_device(&block_class, NULL, label, &match_dev_by_label);
if (!dev)
return -ENODEV;
*devt = dev->devt;
put_device(dev);
return 0;
}
static dev_t __init blk_lookup_devt(const char *name, int partno)
{
dev_t devt = MKDEV(0, 0);
struct class_dev_iter iter;
struct device *dev;
class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
while ((dev = class_dev_iter_next(&iter))) {
struct gendisk *disk = dev_to_disk(dev);
if (strcmp(dev_name(dev), name))
continue;
if (partno < disk->minors) {
/* We need to return the right devno, even
* if the partition doesn't exist yet.
*/
devt = MKDEV(MAJOR(dev->devt),
MINOR(dev->devt) + partno);
} else {
devt = part_devt(disk, partno);
if (devt)
break;
}
}
class_dev_iter_exit(&iter);
return devt;
}
static int __init devt_from_devname(const char *name, dev_t *devt)
{
int part;
char s[32];
char *p;
if (strlen(name) > 31)
return -EINVAL;
strcpy(s, name);
for (p = s; *p; p++) {
if (*p == '/')
*p = '!';
}
*devt = blk_lookup_devt(s, 0);
if (*devt)
return 0;
/*
* Try non-existent, but valid partition, which may only exist after
* opening the device, like partitioned md devices.
*/
while (p > s && isdigit(p[-1]))
p--;
if (p == s || !*p || *p == '0')
return -ENODEV;
/* try disk name without <part number> */
part = simple_strtoul(p, NULL, 10);
*p = '\0';
*devt = blk_lookup_devt(s, part);
if (*devt)
return 0;
/* try disk name without p<part number> */
if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p')
return -ENODEV;
p[-1] = '\0';
*devt = blk_lookup_devt(s, part);
if (*devt)
return 0;
return -ENODEV;
}
static int __init devt_from_devnum(const char *name, dev_t *devt)
{
unsigned maj, min, offset;
char *p, dummy;
if (sscanf(name, "%u:%u%c", &maj, &min, &dummy) == 2 ||
sscanf(name, "%u:%u:%u:%c", &maj, &min, &offset, &dummy) == 3) {
*devt = MKDEV(maj, min);
if (maj != MAJOR(*devt) || min != MINOR(*devt))
return -EINVAL;
} else {
*devt = new_decode_dev(simple_strtoul(name, &p, 16));
if (*p)
return -EINVAL;
}
return 0;
}
/*
* Convert a name into device number. We accept the following variants:
*
* 1) <hex_major><hex_minor> device number in hexadecimal represents itself
* no leading 0x, for example b302.
* 3) /dev/<disk_name> represents the device number of disk
* 4) /dev/<disk_name><decimal> represents the device number
* of partition - device number of disk plus the partition number
* 5) /dev/<disk_name>p<decimal> - same as the above, that form is
* used when disk name of partitioned disk ends on a digit.
* 6) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the
* unique id of a partition if the partition table provides it.
* The UUID may be either an EFI/GPT UUID, or refer to an MSDOS
* partition using the format SSSSSSSS-PP, where SSSSSSSS is a zero-
* filled hex representation of the 32-bit "NT disk signature", and PP
* is a zero-filled hex representation of the 1-based partition number.
* 7) PARTUUID=<UUID>/PARTNROFF=<int> to select a partition in relation to
* a partition with a known unique id.
* 8) <major>:<minor> major and minor number of the device separated by
* a colon.
* 9) PARTLABEL=<name> with name being the GPT partition label.
* MSDOS partitions do not support labels!
*
* If name doesn't have fall into the categories above, we return (0,0).
* block_class is used to check if something is a disk name. If the disk
* name contains slashes, the device name has them replaced with
* bangs.
*/
int __init early_lookup_bdev(const char *name, dev_t *devt)
{
if (strncmp(name, "PARTUUID=", 9) == 0)
return devt_from_partuuid(name + 9, devt);
if (strncmp(name, "PARTLABEL=", 10) == 0)
return devt_from_partlabel(name + 10, devt);
if (strncmp(name, "/dev/", 5) == 0)
return devt_from_devname(name + 5, devt);
return devt_from_devnum(name, devt);
}
static char __init *bdevt_str(dev_t devt, char *buf)
{
if (MAJOR(devt) <= 0xff && MINOR(devt) <= 0xff) {
char tbuf[BDEVT_SIZE];
snprintf(tbuf, BDEVT_SIZE, "%02x%02x", MAJOR(devt), MINOR(devt));
snprintf(buf, BDEVT_SIZE, "%-9s", tbuf);
} else
snprintf(buf, BDEVT_SIZE, "%03x:%05x", MAJOR(devt), MINOR(devt));
return buf;
}
/*
* print a full list of all partitions - intended for places where the root
* filesystem can't be mounted and thus to give the victim some idea of what
* went wrong
*/
void __init printk_all_partitions(void)
{
struct class_dev_iter iter;
struct device *dev;
class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
while ((dev = class_dev_iter_next(&iter))) {
struct gendisk *disk = dev_to_disk(dev);
struct block_device *part;
char devt_buf[BDEVT_SIZE];
unsigned long idx;
/*
* Don't show empty devices or things that have been
* suppressed
*/
if (get_capacity(disk) == 0 || (disk->flags & GENHD_FL_HIDDEN))
continue;
/*
* Note, unlike /proc/partitions, I am showing the numbers in
* hex - the same format as the root= option takes.
*/
rcu_read_lock();
xa_for_each(&disk->part_tbl, idx, part) {
if (!bdev_nr_sectors(part))
continue;
printk("%s%s %10llu %pg %s",
bdev_is_partition(part) ? " " : "",
bdevt_str(part->bd_dev, devt_buf),
bdev_nr_sectors(part) >> 1, part,
part->bd_meta_info ?
part->bd_meta_info->uuid : "");
if (bdev_is_partition(part))
printk("\n");
else if (dev->parent && dev->parent->driver)
printk(" driver: %s\n",
dev->parent->driver->name);
else
printk(" (driver?)\n");
}
rcu_read_unlock();
}
class_dev_iter_exit(&iter);
}

View file

@ -751,7 +751,7 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *buf,
if (!elv_support_iosched(q)) if (!elv_support_iosched(q))
return count; return count;
strlcpy(elevator_name, buf, sizeof(elevator_name)); strscpy(elevator_name, buf, sizeof(elevator_name));
ret = elevator_change(q, strstrip(elevator_name)); ret = elevator_change(q, strstrip(elevator_name));
if (!ret) if (!ret)
return count; return count;

View file

@ -54,7 +54,7 @@ static bool blkdev_dio_unaligned(struct block_device *bdev, loff_t pos,
static ssize_t __blkdev_direct_IO_simple(struct kiocb *iocb, static ssize_t __blkdev_direct_IO_simple(struct kiocb *iocb,
struct iov_iter *iter, unsigned int nr_pages) struct iov_iter *iter, unsigned int nr_pages)
{ {
struct block_device *bdev = iocb->ki_filp->private_data; struct block_device *bdev = I_BDEV(iocb->ki_filp->f_mapping->host);
struct bio_vec inline_vecs[DIO_INLINE_BIO_VECS], *vecs; struct bio_vec inline_vecs[DIO_INLINE_BIO_VECS], *vecs;
loff_t pos = iocb->ki_pos; loff_t pos = iocb->ki_pos;
bool should_dirty = false; bool should_dirty = false;
@ -170,7 +170,7 @@ static void blkdev_bio_end_io(struct bio *bio)
static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter, static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
unsigned int nr_pages) unsigned int nr_pages)
{ {
struct block_device *bdev = iocb->ki_filp->private_data; struct block_device *bdev = I_BDEV(iocb->ki_filp->f_mapping->host);
struct blk_plug plug; struct blk_plug plug;
struct blkdev_dio *dio; struct blkdev_dio *dio;
struct bio *bio; struct bio *bio;
@ -310,7 +310,7 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb,
struct iov_iter *iter, struct iov_iter *iter,
unsigned int nr_pages) unsigned int nr_pages)
{ {
struct block_device *bdev = iocb->ki_filp->private_data; struct block_device *bdev = I_BDEV(iocb->ki_filp->f_mapping->host);
bool is_read = iov_iter_rw(iter) == READ; bool is_read = iov_iter_rw(iter) == READ;
blk_opf_t opf = is_read ? REQ_OP_READ : dio_bio_write_op(iocb); blk_opf_t opf = is_read ? REQ_OP_READ : dio_bio_write_op(iocb);
struct blkdev_dio *dio; struct blkdev_dio *dio;
@ -451,7 +451,7 @@ static loff_t blkdev_llseek(struct file *file, loff_t offset, int whence)
static int blkdev_fsync(struct file *filp, loff_t start, loff_t end, static int blkdev_fsync(struct file *filp, loff_t start, loff_t end,
int datasync) int datasync)
{ {
struct block_device *bdev = filp->private_data; struct block_device *bdev = I_BDEV(filp->f_mapping->host);
int error; int error;
error = file_write_and_wait_range(filp, start, end); error = file_write_and_wait_range(filp, start, end);
@ -470,6 +470,30 @@ static int blkdev_fsync(struct file *filp, loff_t start, loff_t end,
return error; return error;
} }
blk_mode_t file_to_blk_mode(struct file *file)
{
blk_mode_t mode = 0;
if (file->f_mode & FMODE_READ)
mode |= BLK_OPEN_READ;
if (file->f_mode & FMODE_WRITE)
mode |= BLK_OPEN_WRITE;
if (file->private_data)
mode |= BLK_OPEN_EXCL;
if (file->f_flags & O_NDELAY)
mode |= BLK_OPEN_NDELAY;
/*
* If all bits in O_ACCMODE set (aka O_RDWR | O_WRONLY), the floppy
* driver has historically allowed ioctls as if the file was opened for
* writing, but does not allow and actual reads or writes.
*/
if ((file->f_flags & O_ACCMODE) == (O_RDWR | O_WRONLY))
mode |= BLK_OPEN_WRITE_IOCTL;
return mode;
}
static int blkdev_open(struct inode *inode, struct file *filp) static int blkdev_open(struct inode *inode, struct file *filp)
{ {
struct block_device *bdev; struct block_device *bdev;
@ -483,31 +507,29 @@ static int blkdev_open(struct inode *inode, struct file *filp)
filp->f_flags |= O_LARGEFILE; filp->f_flags |= O_LARGEFILE;
filp->f_mode |= FMODE_BUF_RASYNC; filp->f_mode |= FMODE_BUF_RASYNC;
if (filp->f_flags & O_NDELAY) /*
filp->f_mode |= FMODE_NDELAY; * Use the file private data to store the holder for exclusive openes.
* file_to_blk_mode relies on it being present to set BLK_OPEN_EXCL.
*/
if (filp->f_flags & O_EXCL) if (filp->f_flags & O_EXCL)
filp->f_mode |= FMODE_EXCL; filp->private_data = filp;
if ((filp->f_flags & O_ACCMODE) == 3)
filp->f_mode |= FMODE_WRITE_IOCTL;
bdev = blkdev_get_by_dev(inode->i_rdev, filp->f_mode, filp); bdev = blkdev_get_by_dev(inode->i_rdev, file_to_blk_mode(filp),
filp->private_data, NULL);
if (IS_ERR(bdev)) if (IS_ERR(bdev))
return PTR_ERR(bdev); return PTR_ERR(bdev);
if (bdev_nowait(bdev)) if (bdev_nowait(bdev))
filp->f_mode |= FMODE_NOWAIT; filp->f_mode |= FMODE_NOWAIT;
filp->private_data = bdev;
filp->f_mapping = bdev->bd_inode->i_mapping; filp->f_mapping = bdev->bd_inode->i_mapping;
filp->f_wb_err = filemap_sample_wb_err(filp->f_mapping); filp->f_wb_err = filemap_sample_wb_err(filp->f_mapping);
return 0; return 0;
} }
static int blkdev_close(struct inode *inode, struct file *filp) static int blkdev_release(struct inode *inode, struct file *filp)
{ {
struct block_device *bdev = filp->private_data; blkdev_put(I_BDEV(filp->f_mapping->host), filp->private_data);
blkdev_put(bdev, filp->f_mode);
return 0; return 0;
} }
@ -520,10 +542,9 @@ static int blkdev_close(struct inode *inode, struct file *filp)
*/ */
static ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from) static ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from)
{ {
struct block_device *bdev = iocb->ki_filp->private_data; struct block_device *bdev = I_BDEV(iocb->ki_filp->f_mapping->host);
struct inode *bd_inode = bdev->bd_inode; struct inode *bd_inode = bdev->bd_inode;
loff_t size = bdev_nr_bytes(bdev); loff_t size = bdev_nr_bytes(bdev);
struct blk_plug plug;
size_t shorted = 0; size_t shorted = 0;
ssize_t ret; ssize_t ret;
@ -548,18 +569,16 @@ static ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from)
iov_iter_truncate(from, size); iov_iter_truncate(from, size);
} }
blk_start_plug(&plug);
ret = __generic_file_write_iter(iocb, from); ret = __generic_file_write_iter(iocb, from);
if (ret > 0) if (ret > 0)
ret = generic_write_sync(iocb, ret); ret = generic_write_sync(iocb, ret);
iov_iter_reexpand(from, iov_iter_count(from) + shorted); iov_iter_reexpand(from, iov_iter_count(from) + shorted);
blk_finish_plug(&plug);
return ret; return ret;
} }
static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to) static ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to)
{ {
struct block_device *bdev = iocb->ki_filp->private_data; struct block_device *bdev = I_BDEV(iocb->ki_filp->f_mapping->host);
loff_t size = bdev_nr_bytes(bdev); loff_t size = bdev_nr_bytes(bdev);
loff_t pos = iocb->ki_pos; loff_t pos = iocb->ki_pos;
size_t shorted = 0; size_t shorted = 0;
@ -652,7 +671,7 @@ static long blkdev_fallocate(struct file *file, int mode, loff_t start,
filemap_invalidate_lock(inode->i_mapping); filemap_invalidate_lock(inode->i_mapping);
/* Invalidate the page cache, including dirty pages. */ /* Invalidate the page cache, including dirty pages. */
error = truncate_bdev_range(bdev, file->f_mode, start, end); error = truncate_bdev_range(bdev, file_to_blk_mode(file), start, end);
if (error) if (error)
goto fail; goto fail;
@ -693,7 +712,7 @@ static int blkdev_mmap(struct file *file, struct vm_area_struct *vma)
const struct file_operations def_blk_fops = { const struct file_operations def_blk_fops = {
.open = blkdev_open, .open = blkdev_open,
.release = blkdev_close, .release = blkdev_release,
.llseek = blkdev_llseek, .llseek = blkdev_llseek,
.read_iter = blkdev_read_iter, .read_iter = blkdev_read_iter,
.write_iter = blkdev_write_iter, .write_iter = blkdev_write_iter,

View file

@ -25,8 +25,9 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/badblocks.h> #include <linux/badblocks.h>
#include <linux/part_stat.h> #include <linux/part_stat.h>
#include "blk-throttle.h" #include <linux/blktrace_api.h>
#include "blk-throttle.h"
#include "blk.h" #include "blk.h"
#include "blk-mq-sched.h" #include "blk-mq-sched.h"
#include "blk-rq-qos.h" #include "blk-rq-qos.h"
@ -253,7 +254,7 @@ int __register_blkdev(unsigned int major, const char *name,
#ifdef CONFIG_BLOCK_LEGACY_AUTOLOAD #ifdef CONFIG_BLOCK_LEGACY_AUTOLOAD
p->probe = probe; p->probe = probe;
#endif #endif
strlcpy(p->name, name, sizeof(p->name)); strscpy(p->name, name, sizeof(p->name));
p->next = NULL; p->next = NULL;
index = major_to_index(major); index = major_to_index(major);
@ -318,18 +319,6 @@ void blk_free_ext_minor(unsigned int minor)
ida_free(&ext_devt_ida, minor); ida_free(&ext_devt_ida, minor);
} }
static char *bdevt_str(dev_t devt, char *buf)
{
if (MAJOR(devt) <= 0xff && MINOR(devt) <= 0xff) {
char tbuf[BDEVT_SIZE];
snprintf(tbuf, BDEVT_SIZE, "%02x%02x", MAJOR(devt), MINOR(devt));
snprintf(buf, BDEVT_SIZE, "%-9s", tbuf);
} else
snprintf(buf, BDEVT_SIZE, "%03x:%05x", MAJOR(devt), MINOR(devt));
return buf;
}
void disk_uevent(struct gendisk *disk, enum kobject_action action) void disk_uevent(struct gendisk *disk, enum kobject_action action)
{ {
struct block_device *part; struct block_device *part;
@ -351,7 +340,7 @@ void disk_uevent(struct gendisk *disk, enum kobject_action action)
} }
EXPORT_SYMBOL_GPL(disk_uevent); EXPORT_SYMBOL_GPL(disk_uevent);
int disk_scan_partitions(struct gendisk *disk, fmode_t mode) int disk_scan_partitions(struct gendisk *disk, blk_mode_t mode)
{ {
struct block_device *bdev; struct block_device *bdev;
int ret = 0; int ret = 0;
@ -369,18 +358,20 @@ int disk_scan_partitions(struct gendisk *disk, fmode_t mode)
* synchronize with other exclusive openers and other partition * synchronize with other exclusive openers and other partition
* scanners. * scanners.
*/ */
if (!(mode & FMODE_EXCL)) { if (!(mode & BLK_OPEN_EXCL)) {
ret = bd_prepare_to_claim(disk->part0, disk_scan_partitions); ret = bd_prepare_to_claim(disk->part0, disk_scan_partitions,
NULL);
if (ret) if (ret)
return ret; return ret;
} }
set_bit(GD_NEED_PART_SCAN, &disk->state); set_bit(GD_NEED_PART_SCAN, &disk->state);
bdev = blkdev_get_by_dev(disk_devt(disk), mode & ~FMODE_EXCL, NULL); bdev = blkdev_get_by_dev(disk_devt(disk), mode & ~BLK_OPEN_EXCL, NULL,
NULL);
if (IS_ERR(bdev)) if (IS_ERR(bdev))
ret = PTR_ERR(bdev); ret = PTR_ERR(bdev);
else else
blkdev_put(bdev, mode & ~FMODE_EXCL); blkdev_put(bdev, NULL);
/* /*
* If blkdev_get_by_dev() failed early, GD_NEED_PART_SCAN is still set, * If blkdev_get_by_dev() failed early, GD_NEED_PART_SCAN is still set,
@ -388,7 +379,7 @@ int disk_scan_partitions(struct gendisk *disk, fmode_t mode)
* creat partition for underlying disk. * creat partition for underlying disk.
*/ */
clear_bit(GD_NEED_PART_SCAN, &disk->state); clear_bit(GD_NEED_PART_SCAN, &disk->state);
if (!(mode & FMODE_EXCL)) if (!(mode & BLK_OPEN_EXCL))
bd_abort_claiming(disk->part0, disk_scan_partitions); bd_abort_claiming(disk->part0, disk_scan_partitions);
return ret; return ret;
} }
@ -516,7 +507,7 @@ int __must_check device_add_disk(struct device *parent, struct gendisk *disk,
bdev_add(disk->part0, ddev->devt); bdev_add(disk->part0, ddev->devt);
if (get_capacity(disk)) if (get_capacity(disk))
disk_scan_partitions(disk, FMODE_READ); disk_scan_partitions(disk, BLK_OPEN_READ);
/* /*
* Announce the disk and partitions after all partitions are * Announce the disk and partitions after all partitions are
@ -563,6 +554,28 @@ out_exit_elevator:
} }
EXPORT_SYMBOL(device_add_disk); EXPORT_SYMBOL(device_add_disk);
static void blk_report_disk_dead(struct gendisk *disk)
{
struct block_device *bdev;
unsigned long idx;
rcu_read_lock();
xa_for_each(&disk->part_tbl, idx, bdev) {
if (!kobject_get_unless_zero(&bdev->bd_device.kobj))
continue;
rcu_read_unlock();
mutex_lock(&bdev->bd_holder_lock);
if (bdev->bd_holder_ops && bdev->bd_holder_ops->mark_dead)
bdev->bd_holder_ops->mark_dead(bdev);
mutex_unlock(&bdev->bd_holder_lock);
put_device(&bdev->bd_device);
rcu_read_lock();
}
rcu_read_unlock();
}
/** /**
* blk_mark_disk_dead - mark a disk as dead * blk_mark_disk_dead - mark a disk as dead
* @disk: disk to mark as dead * @disk: disk to mark as dead
@ -572,13 +585,26 @@ EXPORT_SYMBOL(device_add_disk);
*/ */
void blk_mark_disk_dead(struct gendisk *disk) void blk_mark_disk_dead(struct gendisk *disk)
{ {
set_bit(GD_DEAD, &disk->state); /*
blk_queue_start_drain(disk->queue); * Fail any new I/O.
*/
if (test_and_set_bit(GD_DEAD, &disk->state))
return;
if (test_bit(GD_OWNS_QUEUE, &disk->state))
blk_queue_flag_set(QUEUE_FLAG_DYING, disk->queue);
/* /*
* Stop buffered writers from dirtying pages that can't be written out. * Stop buffered writers from dirtying pages that can't be written out.
*/ */
set_capacity_and_notify(disk, 0); set_capacity(disk, 0);
/*
* Prevent new I/O from crossing bio_queue_enter().
*/
blk_queue_start_drain(disk->queue);
blk_report_disk_dead(disk);
} }
EXPORT_SYMBOL_GPL(blk_mark_disk_dead); EXPORT_SYMBOL_GPL(blk_mark_disk_dead);
@ -604,6 +630,8 @@ EXPORT_SYMBOL_GPL(blk_mark_disk_dead);
void del_gendisk(struct gendisk *disk) void del_gendisk(struct gendisk *disk)
{ {
struct request_queue *q = disk->queue; struct request_queue *q = disk->queue;
struct block_device *part;
unsigned long idx;
might_sleep(); might_sleep();
@ -612,26 +640,27 @@ void del_gendisk(struct gendisk *disk)
disk_del_events(disk); disk_del_events(disk);
/*
* Prevent new openers by unlinked the bdev inode, and write out
* dirty data before marking the disk dead and stopping all I/O.
*/
mutex_lock(&disk->open_mutex); mutex_lock(&disk->open_mutex);
remove_inode_hash(disk->part0->bd_inode); xa_for_each(&disk->part_tbl, idx, part) {
blk_drop_partitions(disk); remove_inode_hash(part->bd_inode);
fsync_bdev(part);
__invalidate_device(part, true);
}
mutex_unlock(&disk->open_mutex); mutex_unlock(&disk->open_mutex);
fsync_bdev(disk->part0); blk_mark_disk_dead(disk);
__invalidate_device(disk->part0, true);
/* /*
* Fail any new I/O. * Drop all partitions now that the disk is marked dead.
*/ */
set_bit(GD_DEAD, &disk->state); mutex_lock(&disk->open_mutex);
if (test_bit(GD_OWNS_QUEUE, &disk->state)) xa_for_each_start(&disk->part_tbl, idx, part, 1)
blk_queue_flag_set(QUEUE_FLAG_DYING, q); drop_partition(part);
set_capacity(disk, 0); mutex_unlock(&disk->open_mutex);
/*
* Prevent new I/O from crossing bio_queue_enter().
*/
blk_queue_start_drain(q);
if (!(disk->flags & GENHD_FL_HIDDEN)) { if (!(disk->flags & GENHD_FL_HIDDEN)) {
sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi"); sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi");
@ -755,57 +784,6 @@ void blk_request_module(dev_t devt)
} }
#endif /* CONFIG_BLOCK_LEGACY_AUTOLOAD */ #endif /* CONFIG_BLOCK_LEGACY_AUTOLOAD */
/*
* print a full list of all partitions - intended for places where the root
* filesystem can't be mounted and thus to give the victim some idea of what
* went wrong
*/
void __init printk_all_partitions(void)
{
struct class_dev_iter iter;
struct device *dev;
class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
while ((dev = class_dev_iter_next(&iter))) {
struct gendisk *disk = dev_to_disk(dev);
struct block_device *part;
char devt_buf[BDEVT_SIZE];
unsigned long idx;
/*
* Don't show empty devices or things that have been
* suppressed
*/
if (get_capacity(disk) == 0 || (disk->flags & GENHD_FL_HIDDEN))
continue;
/*
* Note, unlike /proc/partitions, I am showing the numbers in
* hex - the same format as the root= option takes.
*/
rcu_read_lock();
xa_for_each(&disk->part_tbl, idx, part) {
if (!bdev_nr_sectors(part))
continue;
printk("%s%s %10llu %pg %s",
bdev_is_partition(part) ? " " : "",
bdevt_str(part->bd_dev, devt_buf),
bdev_nr_sectors(part) >> 1, part,
part->bd_meta_info ?
part->bd_meta_info->uuid : "");
if (bdev_is_partition(part))
printk("\n");
else if (dev->parent && dev->parent->driver)
printk(" driver: %s\n",
dev->parent->driver->name);
else
printk(" (driver?)\n");
}
rcu_read_unlock();
}
class_dev_iter_exit(&iter);
}
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
/* iterator */ /* iterator */
static void *disk_seqf_start(struct seq_file *seqf, loff_t *pos) static void *disk_seqf_start(struct seq_file *seqf, loff_t *pos)
@ -1171,6 +1149,8 @@ static void disk_release(struct device *dev)
might_sleep(); might_sleep();
WARN_ON_ONCE(disk_live(disk)); WARN_ON_ONCE(disk_live(disk));
blk_trace_remove(disk->queue);
/* /*
* To undo the all initialization from blk_mq_init_allocated_queue in * To undo the all initialization from blk_mq_init_allocated_queue in
* case of a probe failure where add_disk is never called we have to * case of a probe failure where add_disk is never called we have to
@ -1339,35 +1319,6 @@ dev_t part_devt(struct gendisk *disk, u8 partno)
return devt; return devt;
} }
dev_t blk_lookup_devt(const char *name, int partno)
{
dev_t devt = MKDEV(0, 0);
struct class_dev_iter iter;
struct device *dev;
class_dev_iter_init(&iter, &block_class, NULL, &disk_type);
while ((dev = class_dev_iter_next(&iter))) {
struct gendisk *disk = dev_to_disk(dev);
if (strcmp(dev_name(dev), name))
continue;
if (partno < disk->minors) {
/* We need to return the right devno, even
* if the partition doesn't exist yet.
*/
devt = MKDEV(MAJOR(dev->devt),
MINOR(dev->devt) + partno);
} else {
devt = part_devt(disk, partno);
if (devt)
break;
}
}
class_dev_iter_exit(&iter);
return devt;
}
struct gendisk *__alloc_disk_node(struct request_queue *q, int node_id, struct gendisk *__alloc_disk_node(struct request_queue *q, int node_id,
struct lock_class_key *lkclass) struct lock_class_key *lkclass)
{ {

View file

@ -82,7 +82,7 @@ static int compat_blkpg_ioctl(struct block_device *bdev,
} }
#endif #endif
static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode, static int blk_ioctl_discard(struct block_device *bdev, blk_mode_t mode,
unsigned long arg) unsigned long arg)
{ {
uint64_t range[2]; uint64_t range[2];
@ -90,7 +90,7 @@ static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode,
struct inode *inode = bdev->bd_inode; struct inode *inode = bdev->bd_inode;
int err; int err;
if (!(mode & FMODE_WRITE)) if (!(mode & BLK_OPEN_WRITE))
return -EBADF; return -EBADF;
if (!bdev_max_discard_sectors(bdev)) if (!bdev_max_discard_sectors(bdev))
@ -120,14 +120,14 @@ fail:
return err; return err;
} }
static int blk_ioctl_secure_erase(struct block_device *bdev, fmode_t mode, static int blk_ioctl_secure_erase(struct block_device *bdev, blk_mode_t mode,
void __user *argp) void __user *argp)
{ {
uint64_t start, len; uint64_t start, len;
uint64_t range[2]; uint64_t range[2];
int err; int err;
if (!(mode & FMODE_WRITE)) if (!(mode & BLK_OPEN_WRITE))
return -EBADF; return -EBADF;
if (!bdev_max_secure_erase_sectors(bdev)) if (!bdev_max_secure_erase_sectors(bdev))
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -151,7 +151,7 @@ static int blk_ioctl_secure_erase(struct block_device *bdev, fmode_t mode,
} }
static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode, static int blk_ioctl_zeroout(struct block_device *bdev, blk_mode_t mode,
unsigned long arg) unsigned long arg)
{ {
uint64_t range[2]; uint64_t range[2];
@ -159,7 +159,7 @@ static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode,
struct inode *inode = bdev->bd_inode; struct inode *inode = bdev->bd_inode;
int err; int err;
if (!(mode & FMODE_WRITE)) if (!(mode & BLK_OPEN_WRITE))
return -EBADF; return -EBADF;
if (copy_from_user(range, (void __user *)arg, sizeof(range))) if (copy_from_user(range, (void __user *)arg, sizeof(range)))
@ -240,7 +240,7 @@ static int compat_put_ulong(compat_ulong_t __user *argp, compat_ulong_t val)
* drivers that implement only commands that are completely compatible * drivers that implement only commands that are completely compatible
* between 32-bit and 64-bit user space * between 32-bit and 64-bit user space
*/ */
int blkdev_compat_ptr_ioctl(struct block_device *bdev, fmode_t mode, int blkdev_compat_ptr_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned cmd, unsigned long arg) unsigned cmd, unsigned long arg)
{ {
struct gendisk *disk = bdev->bd_disk; struct gendisk *disk = bdev->bd_disk;
@ -254,13 +254,28 @@ int blkdev_compat_ptr_ioctl(struct block_device *bdev, fmode_t mode,
EXPORT_SYMBOL(blkdev_compat_ptr_ioctl); EXPORT_SYMBOL(blkdev_compat_ptr_ioctl);
#endif #endif
static int blkdev_pr_register(struct block_device *bdev, static bool blkdev_pr_allowed(struct block_device *bdev, blk_mode_t mode)
{
/* no sense to make reservations for partitions */
if (bdev_is_partition(bdev))
return false;
if (capable(CAP_SYS_ADMIN))
return true;
/*
* Only allow unprivileged reservations if the file descriptor is open
* for writing.
*/
return mode & BLK_OPEN_WRITE;
}
static int blkdev_pr_register(struct block_device *bdev, blk_mode_t mode,
struct pr_registration __user *arg) struct pr_registration __user *arg)
{ {
const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
struct pr_registration reg; struct pr_registration reg;
if (!capable(CAP_SYS_ADMIN)) if (!blkdev_pr_allowed(bdev, mode))
return -EPERM; return -EPERM;
if (!ops || !ops->pr_register) if (!ops || !ops->pr_register)
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -272,13 +287,13 @@ static int blkdev_pr_register(struct block_device *bdev,
return ops->pr_register(bdev, reg.old_key, reg.new_key, reg.flags); return ops->pr_register(bdev, reg.old_key, reg.new_key, reg.flags);
} }
static int blkdev_pr_reserve(struct block_device *bdev, static int blkdev_pr_reserve(struct block_device *bdev, blk_mode_t mode,
struct pr_reservation __user *arg) struct pr_reservation __user *arg)
{ {
const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
struct pr_reservation rsv; struct pr_reservation rsv;
if (!capable(CAP_SYS_ADMIN)) if (!blkdev_pr_allowed(bdev, mode))
return -EPERM; return -EPERM;
if (!ops || !ops->pr_reserve) if (!ops || !ops->pr_reserve)
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -290,13 +305,13 @@ static int blkdev_pr_reserve(struct block_device *bdev,
return ops->pr_reserve(bdev, rsv.key, rsv.type, rsv.flags); return ops->pr_reserve(bdev, rsv.key, rsv.type, rsv.flags);
} }
static int blkdev_pr_release(struct block_device *bdev, static int blkdev_pr_release(struct block_device *bdev, blk_mode_t mode,
struct pr_reservation __user *arg) struct pr_reservation __user *arg)
{ {
const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
struct pr_reservation rsv; struct pr_reservation rsv;
if (!capable(CAP_SYS_ADMIN)) if (!blkdev_pr_allowed(bdev, mode))
return -EPERM; return -EPERM;
if (!ops || !ops->pr_release) if (!ops || !ops->pr_release)
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -308,13 +323,13 @@ static int blkdev_pr_release(struct block_device *bdev,
return ops->pr_release(bdev, rsv.key, rsv.type); return ops->pr_release(bdev, rsv.key, rsv.type);
} }
static int blkdev_pr_preempt(struct block_device *bdev, static int blkdev_pr_preempt(struct block_device *bdev, blk_mode_t mode,
struct pr_preempt __user *arg, bool abort) struct pr_preempt __user *arg, bool abort)
{ {
const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
struct pr_preempt p; struct pr_preempt p;
if (!capable(CAP_SYS_ADMIN)) if (!blkdev_pr_allowed(bdev, mode))
return -EPERM; return -EPERM;
if (!ops || !ops->pr_preempt) if (!ops || !ops->pr_preempt)
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -326,13 +341,13 @@ static int blkdev_pr_preempt(struct block_device *bdev,
return ops->pr_preempt(bdev, p.old_key, p.new_key, p.type, abort); return ops->pr_preempt(bdev, p.old_key, p.new_key, p.type, abort);
} }
static int blkdev_pr_clear(struct block_device *bdev, static int blkdev_pr_clear(struct block_device *bdev, blk_mode_t mode,
struct pr_clear __user *arg) struct pr_clear __user *arg)
{ {
const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops;
struct pr_clear c; struct pr_clear c;
if (!capable(CAP_SYS_ADMIN)) if (!blkdev_pr_allowed(bdev, mode))
return -EPERM; return -EPERM;
if (!ops || !ops->pr_clear) if (!ops || !ops->pr_clear)
return -EOPNOTSUPP; return -EOPNOTSUPP;
@ -344,8 +359,8 @@ static int blkdev_pr_clear(struct block_device *bdev,
return ops->pr_clear(bdev, c.key); return ops->pr_clear(bdev, c.key);
} }
static int blkdev_flushbuf(struct block_device *bdev, fmode_t mode, static int blkdev_flushbuf(struct block_device *bdev, unsigned cmd,
unsigned cmd, unsigned long arg) unsigned long arg)
{ {
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
@ -354,8 +369,8 @@ static int blkdev_flushbuf(struct block_device *bdev, fmode_t mode,
return 0; return 0;
} }
static int blkdev_roset(struct block_device *bdev, fmode_t mode, static int blkdev_roset(struct block_device *bdev, unsigned cmd,
unsigned cmd, unsigned long arg) unsigned long arg)
{ {
int ret, n; int ret, n;
@ -439,7 +454,7 @@ static int compat_hdio_getgeo(struct block_device *bdev,
#endif #endif
/* set the logical block size */ /* set the logical block size */
static int blkdev_bszset(struct block_device *bdev, fmode_t mode, static int blkdev_bszset(struct block_device *bdev, blk_mode_t mode,
int __user *argp) int __user *argp)
{ {
int ret, n; int ret, n;
@ -451,13 +466,13 @@ static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
if (get_user(n, argp)) if (get_user(n, argp))
return -EFAULT; return -EFAULT;
if (mode & FMODE_EXCL) if (mode & BLK_OPEN_EXCL)
return set_blocksize(bdev, n); return set_blocksize(bdev, n);
if (IS_ERR(blkdev_get_by_dev(bdev->bd_dev, mode | FMODE_EXCL, &bdev))) if (IS_ERR(blkdev_get_by_dev(bdev->bd_dev, mode, &bdev, NULL)))
return -EBUSY; return -EBUSY;
ret = set_blocksize(bdev, n); ret = set_blocksize(bdev, n);
blkdev_put(bdev, mode | FMODE_EXCL); blkdev_put(bdev, &bdev);
return ret; return ret;
} }
@ -467,7 +482,7 @@ static int blkdev_bszset(struct block_device *bdev, fmode_t mode,
* user space. Note the separate arg/argp parameters that are needed * user space. Note the separate arg/argp parameters that are needed
* to deal with the compat_ptr() conversion. * to deal with the compat_ptr() conversion.
*/ */
static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode, static int blkdev_common_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long arg, unsigned int cmd, unsigned long arg,
void __user *argp) void __user *argp)
{ {
@ -475,9 +490,9 @@ static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
switch (cmd) { switch (cmd) {
case BLKFLSBUF: case BLKFLSBUF:
return blkdev_flushbuf(bdev, mode, cmd, arg); return blkdev_flushbuf(bdev, cmd, arg);
case BLKROSET: case BLKROSET:
return blkdev_roset(bdev, mode, cmd, arg); return blkdev_roset(bdev, cmd, arg);
case BLKDISCARD: case BLKDISCARD:
return blk_ioctl_discard(bdev, mode, arg); return blk_ioctl_discard(bdev, mode, arg);
case BLKSECDISCARD: case BLKSECDISCARD:
@ -487,7 +502,7 @@ static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
case BLKGETDISKSEQ: case BLKGETDISKSEQ:
return put_u64(argp, bdev->bd_disk->diskseq); return put_u64(argp, bdev->bd_disk->diskseq);
case BLKREPORTZONE: case BLKREPORTZONE:
return blkdev_report_zones_ioctl(bdev, mode, cmd, arg); return blkdev_report_zones_ioctl(bdev, cmd, arg);
case BLKRESETZONE: case BLKRESETZONE:
case BLKOPENZONE: case BLKOPENZONE:
case BLKCLOSEZONE: case BLKCLOSEZONE:
@ -534,17 +549,17 @@ static int blkdev_common_ioctl(struct block_device *bdev, fmode_t mode,
case BLKTRACETEARDOWN: case BLKTRACETEARDOWN:
return blk_trace_ioctl(bdev, cmd, argp); return blk_trace_ioctl(bdev, cmd, argp);
case IOC_PR_REGISTER: case IOC_PR_REGISTER:
return blkdev_pr_register(bdev, argp); return blkdev_pr_register(bdev, mode, argp);
case IOC_PR_RESERVE: case IOC_PR_RESERVE:
return blkdev_pr_reserve(bdev, argp); return blkdev_pr_reserve(bdev, mode, argp);
case IOC_PR_RELEASE: case IOC_PR_RELEASE:
return blkdev_pr_release(bdev, argp); return blkdev_pr_release(bdev, mode, argp);
case IOC_PR_PREEMPT: case IOC_PR_PREEMPT:
return blkdev_pr_preempt(bdev, argp, false); return blkdev_pr_preempt(bdev, mode, argp, false);
case IOC_PR_PREEMPT_ABORT: case IOC_PR_PREEMPT_ABORT:
return blkdev_pr_preempt(bdev, argp, true); return blkdev_pr_preempt(bdev, mode, argp, true);
case IOC_PR_CLEAR: case IOC_PR_CLEAR:
return blkdev_pr_clear(bdev, argp); return blkdev_pr_clear(bdev, mode, argp);
default: default:
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }
@ -560,18 +575,9 @@ long blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{ {
struct block_device *bdev = I_BDEV(file->f_mapping->host); struct block_device *bdev = I_BDEV(file->f_mapping->host);
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
fmode_t mode = file->f_mode; blk_mode_t mode = file_to_blk_mode(file);
int ret; int ret;
/*
* O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
* to updated it before every ioctl.
*/
if (file->f_flags & O_NDELAY)
mode |= FMODE_NDELAY;
else
mode &= ~FMODE_NDELAY;
switch (cmd) { switch (cmd) {
/* These need separate implementations for the data structure */ /* These need separate implementations for the data structure */
case HDIO_GETGEO: case HDIO_GETGEO:
@ -630,16 +636,7 @@ long compat_blkdev_ioctl(struct file *file, unsigned cmd, unsigned long arg)
void __user *argp = compat_ptr(arg); void __user *argp = compat_ptr(arg);
struct block_device *bdev = I_BDEV(file->f_mapping->host); struct block_device *bdev = I_BDEV(file->f_mapping->host);
struct gendisk *disk = bdev->bd_disk; struct gendisk *disk = bdev->bd_disk;
fmode_t mode = file->f_mode; blk_mode_t mode = file_to_blk_mode(file);
/*
* O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have
* to updated it before every ioctl.
*/
if (file->f_flags & O_NDELAY)
mode |= FMODE_NDELAY;
else
mode &= ~FMODE_NDELAY;
switch (cmd) { switch (cmd) {
/* These need separate implementations for the data structure */ /* These need separate implementations for the data structure */

View file

@ -74,8 +74,8 @@ struct dd_per_prio {
struct list_head dispatch; struct list_head dispatch;
struct rb_root sort_list[DD_DIR_COUNT]; struct rb_root sort_list[DD_DIR_COUNT];
struct list_head fifo_list[DD_DIR_COUNT]; struct list_head fifo_list[DD_DIR_COUNT];
/* Next request in FIFO order. Read, write or both are NULL. */ /* Position of the most recently dispatched request. */
struct request *next_rq[DD_DIR_COUNT]; sector_t latest_pos[DD_DIR_COUNT];
struct io_stats_per_prio stats; struct io_stats_per_prio stats;
}; };
@ -156,6 +156,40 @@ deadline_latter_request(struct request *rq)
return NULL; return NULL;
} }
/*
* Return the first request for which blk_rq_pos() >= @pos. For zoned devices,
* return the first request after the start of the zone containing @pos.
*/
static inline struct request *deadline_from_pos(struct dd_per_prio *per_prio,
enum dd_data_dir data_dir, sector_t pos)
{
struct rb_node *node = per_prio->sort_list[data_dir].rb_node;
struct request *rq, *res = NULL;
if (!node)
return NULL;
rq = rb_entry_rq(node);
/*
* A zoned write may have been requeued with a starting position that
* is below that of the most recently dispatched request. Hence, for
* zoned writes, start searching from the start of a zone.
*/
if (blk_rq_is_seq_zoned_write(rq))
pos -= round_down(pos, rq->q->limits.chunk_sectors);
while (node) {
rq = rb_entry_rq(node);
if (blk_rq_pos(rq) >= pos) {
res = rq;
node = node->rb_left;
} else {
node = node->rb_right;
}
}
return res;
}
static void static void
deadline_add_rq_rb(struct dd_per_prio *per_prio, struct request *rq) deadline_add_rq_rb(struct dd_per_prio *per_prio, struct request *rq)
{ {
@ -167,11 +201,6 @@ deadline_add_rq_rb(struct dd_per_prio *per_prio, struct request *rq)
static inline void static inline void
deadline_del_rq_rb(struct dd_per_prio *per_prio, struct request *rq) deadline_del_rq_rb(struct dd_per_prio *per_prio, struct request *rq)
{ {
const enum dd_data_dir data_dir = rq_data_dir(rq);
if (per_prio->next_rq[data_dir] == rq)
per_prio->next_rq[data_dir] = deadline_latter_request(rq);
elv_rb_del(deadline_rb_root(per_prio, rq), rq); elv_rb_del(deadline_rb_root(per_prio, rq), rq);
} }
@ -251,10 +280,6 @@ static void
deadline_move_request(struct deadline_data *dd, struct dd_per_prio *per_prio, deadline_move_request(struct deadline_data *dd, struct dd_per_prio *per_prio,
struct request *rq) struct request *rq)
{ {
const enum dd_data_dir data_dir = rq_data_dir(rq);
per_prio->next_rq[data_dir] = deadline_latter_request(rq);
/* /*
* take it off the sort and fifo list * take it off the sort and fifo list
*/ */
@ -272,21 +297,15 @@ static u32 dd_queued(struct deadline_data *dd, enum dd_prio prio)
} }
/* /*
* deadline_check_fifo returns 0 if there are no expired requests on the fifo, * deadline_check_fifo returns true if and only if there are expired requests
* 1 otherwise. Requires !list_empty(&dd->fifo_list[data_dir]) * in the FIFO list. Requires !list_empty(&dd->fifo_list[data_dir]).
*/ */
static inline int deadline_check_fifo(struct dd_per_prio *per_prio, static inline bool deadline_check_fifo(struct dd_per_prio *per_prio,
enum dd_data_dir data_dir) enum dd_data_dir data_dir)
{ {
struct request *rq = rq_entry_fifo(per_prio->fifo_list[data_dir].next); struct request *rq = rq_entry_fifo(per_prio->fifo_list[data_dir].next);
/* return time_is_before_eq_jiffies((unsigned long)rq->fifo_time);
* rq is expired!
*/
if (time_after_eq(jiffies, (unsigned long)rq->fifo_time))
return 1;
return 0;
} }
/* /*
@ -310,14 +329,11 @@ static struct request *deadline_skip_seq_writes(struct deadline_data *dd,
struct request *rq) struct request *rq)
{ {
sector_t pos = blk_rq_pos(rq); sector_t pos = blk_rq_pos(rq);
sector_t skipped_sectors = 0;
while (rq) { do {
if (blk_rq_pos(rq) != pos + skipped_sectors) pos += blk_rq_sectors(rq);
break;
skipped_sectors += blk_rq_sectors(rq);
rq = deadline_latter_request(rq); rq = deadline_latter_request(rq);
} } while (rq && blk_rq_pos(rq) == pos);
return rq; return rq;
} }
@ -330,7 +346,7 @@ static struct request *
deadline_fifo_request(struct deadline_data *dd, struct dd_per_prio *per_prio, deadline_fifo_request(struct deadline_data *dd, struct dd_per_prio *per_prio,
enum dd_data_dir data_dir) enum dd_data_dir data_dir)
{ {
struct request *rq; struct request *rq, *rb_rq, *next;
unsigned long flags; unsigned long flags;
if (list_empty(&per_prio->fifo_list[data_dir])) if (list_empty(&per_prio->fifo_list[data_dir]))
@ -348,7 +364,12 @@ deadline_fifo_request(struct deadline_data *dd, struct dd_per_prio *per_prio,
* zones and these zones are unlocked. * zones and these zones are unlocked.
*/ */
spin_lock_irqsave(&dd->zone_lock, flags); spin_lock_irqsave(&dd->zone_lock, flags);
list_for_each_entry(rq, &per_prio->fifo_list[DD_WRITE], queuelist) { list_for_each_entry_safe(rq, next, &per_prio->fifo_list[DD_WRITE],
queuelist) {
/* Check whether a prior request exists for the same zone. */
rb_rq = deadline_from_pos(per_prio, data_dir, blk_rq_pos(rq));
if (rb_rq && blk_rq_pos(rb_rq) < blk_rq_pos(rq))
rq = rb_rq;
if (blk_req_can_dispatch_to_zone(rq) && if (blk_req_can_dispatch_to_zone(rq) &&
(blk_queue_nonrot(rq->q) || (blk_queue_nonrot(rq->q) ||
!deadline_is_seq_write(dd, rq))) !deadline_is_seq_write(dd, rq)))
@ -372,7 +393,8 @@ deadline_next_request(struct deadline_data *dd, struct dd_per_prio *per_prio,
struct request *rq; struct request *rq;
unsigned long flags; unsigned long flags;
rq = per_prio->next_rq[data_dir]; rq = deadline_from_pos(per_prio, data_dir,
per_prio->latest_pos[data_dir]);
if (!rq) if (!rq)
return NULL; return NULL;
@ -435,6 +457,7 @@ static struct request *__dd_dispatch_request(struct deadline_data *dd,
if (started_after(dd, rq, latest_start)) if (started_after(dd, rq, latest_start))
return NULL; return NULL;
list_del_init(&rq->queuelist); list_del_init(&rq->queuelist);
data_dir = rq_data_dir(rq);
goto done; goto done;
} }
@ -442,9 +465,11 @@ static struct request *__dd_dispatch_request(struct deadline_data *dd,
* batches are currently reads XOR writes * batches are currently reads XOR writes
*/ */
rq = deadline_next_request(dd, per_prio, dd->last_dir); rq = deadline_next_request(dd, per_prio, dd->last_dir);
if (rq && dd->batching < dd->fifo_batch) if (rq && dd->batching < dd->fifo_batch) {
/* we have a next request are still entitled to batch */ /* we have a next request and are still entitled to batch */
data_dir = rq_data_dir(rq);
goto dispatch_request; goto dispatch_request;
}
/* /*
* at this point we are not running a batch. select the appropriate * at this point we are not running a batch. select the appropriate
@ -522,6 +547,7 @@ dispatch_request:
done: done:
ioprio_class = dd_rq_ioclass(rq); ioprio_class = dd_rq_ioclass(rq);
prio = ioprio_class_to_prio[ioprio_class]; prio = ioprio_class_to_prio[ioprio_class];
dd->per_prio[prio].latest_pos[data_dir] = blk_rq_pos(rq);
dd->per_prio[prio].stats.dispatched++; dd->per_prio[prio].stats.dispatched++;
/* /*
* If the request needs its target zone locked, do it. * If the request needs its target zone locked, do it.
@ -766,7 +792,7 @@ static bool dd_bio_merge(struct request_queue *q, struct bio *bio,
* add rq to rbtree and fifo * add rq to rbtree and fifo
*/ */
static void dd_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq, static void dd_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
blk_insert_t flags) blk_insert_t flags, struct list_head *free)
{ {
struct request_queue *q = hctx->queue; struct request_queue *q = hctx->queue;
struct deadline_data *dd = q->elevator->elevator_data; struct deadline_data *dd = q->elevator->elevator_data;
@ -775,7 +801,6 @@ static void dd_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
u8 ioprio_class = IOPRIO_PRIO_CLASS(ioprio); u8 ioprio_class = IOPRIO_PRIO_CLASS(ioprio);
struct dd_per_prio *per_prio; struct dd_per_prio *per_prio;
enum dd_prio prio; enum dd_prio prio;
LIST_HEAD(free);
lockdep_assert_held(&dd->lock); lockdep_assert_held(&dd->lock);
@ -792,10 +817,8 @@ static void dd_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
rq->elv.priv[0] = (void *)(uintptr_t)1; rq->elv.priv[0] = (void *)(uintptr_t)1;
} }
if (blk_mq_sched_try_insert_merge(q, rq, &free)) { if (blk_mq_sched_try_insert_merge(q, rq, free))
blk_mq_free_requests(&free);
return; return;
}
trace_block_rq_insert(rq); trace_block_rq_insert(rq);
@ -803,6 +826,8 @@ static void dd_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
list_add(&rq->queuelist, &per_prio->dispatch); list_add(&rq->queuelist, &per_prio->dispatch);
rq->fifo_time = jiffies; rq->fifo_time = jiffies;
} else { } else {
struct list_head *insert_before;
deadline_add_rq_rb(per_prio, rq); deadline_add_rq_rb(per_prio, rq);
if (rq_mergeable(rq)) { if (rq_mergeable(rq)) {
@ -815,7 +840,20 @@ static void dd_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq,
* set expire time and add to fifo list * set expire time and add to fifo list
*/ */
rq->fifo_time = jiffies + dd->fifo_expire[data_dir]; rq->fifo_time = jiffies + dd->fifo_expire[data_dir];
list_add_tail(&rq->queuelist, &per_prio->fifo_list[data_dir]); insert_before = &per_prio->fifo_list[data_dir];
#ifdef CONFIG_BLK_DEV_ZONED
/*
* Insert zoned writes such that requests are sorted by
* position per zone.
*/
if (blk_rq_is_seq_zoned_write(rq)) {
struct request *rq2 = deadline_latter_request(rq);
if (rq2 && blk_rq_zone_no(rq2) == blk_rq_zone_no(rq))
insert_before = &rq2->queuelist;
}
#endif
list_add_tail(&rq->queuelist, insert_before);
} }
} }
@ -828,6 +866,7 @@ static void dd_insert_requests(struct blk_mq_hw_ctx *hctx,
{ {
struct request_queue *q = hctx->queue; struct request_queue *q = hctx->queue;
struct deadline_data *dd = q->elevator->elevator_data; struct deadline_data *dd = q->elevator->elevator_data;
LIST_HEAD(free);
spin_lock(&dd->lock); spin_lock(&dd->lock);
while (!list_empty(list)) { while (!list_empty(list)) {
@ -835,9 +874,11 @@ static void dd_insert_requests(struct blk_mq_hw_ctx *hctx,
rq = list_first_entry(list, struct request, queuelist); rq = list_first_entry(list, struct request, queuelist);
list_del_init(&rq->queuelist); list_del_init(&rq->queuelist);
dd_insert_request(hctx, rq, flags); dd_insert_request(hctx, rq, flags, &free);
} }
spin_unlock(&dd->lock); spin_unlock(&dd->lock);
blk_mq_free_requests(&free);
} }
/* Callback from inside blk_mq_rq_ctx_init(). */ /* Callback from inside blk_mq_rq_ctx_init(). */
@ -1035,8 +1076,10 @@ static int deadline_##name##_next_rq_show(void *data, \
struct request_queue *q = data; \ struct request_queue *q = data; \
struct deadline_data *dd = q->elevator->elevator_data; \ struct deadline_data *dd = q->elevator->elevator_data; \
struct dd_per_prio *per_prio = &dd->per_prio[prio]; \ struct dd_per_prio *per_prio = &dd->per_prio[prio]; \
struct request *rq = per_prio->next_rq[data_dir]; \ struct request *rq; \
\ \
rq = deadline_from_pos(per_prio, data_dir, \
per_prio->latest_pos[data_dir]); \
if (rq) \ if (rq) \
__blk_mq_debugfs_rq_show(m, rq); \ __blk_mq_debugfs_rq_show(m, rq); \
return 0; \ return 0; \

View file

@ -11,10 +11,18 @@
#define pr_fmt(fmt) fmt #define pr_fmt(fmt) fmt
#include <linux/types.h> #include <linux/types.h>
#include <linux/mm_types.h>
#include <linux/overflow.h>
#include <linux/affs_hardblocks.h> #include <linux/affs_hardblocks.h>
#include "check.h" #include "check.h"
/* magic offsets in partition DosEnvVec */
#define NR_HD 3
#define NR_SECT 5
#define LO_CYL 9
#define HI_CYL 10
static __inline__ u32 static __inline__ u32
checksum_block(__be32 *m, int size) checksum_block(__be32 *m, int size)
{ {
@ -31,8 +39,12 @@ int amiga_partition(struct parsed_partitions *state)
unsigned char *data; unsigned char *data;
struct RigidDiskBlock *rdb; struct RigidDiskBlock *rdb;
struct PartitionBlock *pb; struct PartitionBlock *pb;
int start_sect, nr_sects, blk, part, res = 0; u64 start_sect, nr_sects;
int blksize = 1; /* Multiplier for disk block size */ sector_t blk, end_sect;
u32 cylblk; /* rdb_CylBlocks = nr_heads*sect_per_track */
u32 nr_hd, nr_sect, lo_cyl, hi_cyl;
int part, res = 0;
unsigned int blksize = 1; /* Multiplier for disk block size */
int slot = 1; int slot = 1;
for (blk = 0; ; blk++, put_dev_sector(sect)) { for (blk = 0; ; blk++, put_dev_sector(sect)) {
@ -40,7 +52,7 @@ int amiga_partition(struct parsed_partitions *state)
goto rdb_done; goto rdb_done;
data = read_part_sector(state, blk, &sect); data = read_part_sector(state, blk, &sect);
if (!data) { if (!data) {
pr_err("Dev %s: unable to read RDB block %d\n", pr_err("Dev %s: unable to read RDB block %llu\n",
state->disk->disk_name, blk); state->disk->disk_name, blk);
res = -1; res = -1;
goto rdb_done; goto rdb_done;
@ -57,12 +69,12 @@ int amiga_partition(struct parsed_partitions *state)
*(__be32 *)(data+0xdc) = 0; *(__be32 *)(data+0xdc) = 0;
if (checksum_block((__be32 *)data, if (checksum_block((__be32 *)data,
be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)==0) { be32_to_cpu(rdb->rdb_SummedLongs) & 0x7F)==0) {
pr_err("Trashed word at 0xd0 in block %d ignored in checksum calculation\n", pr_err("Trashed word at 0xd0 in block %llu ignored in checksum calculation\n",
blk); blk);
break; break;
} }
pr_err("Dev %s: RDB in block %d has bad checksum\n", pr_err("Dev %s: RDB in block %llu has bad checksum\n",
state->disk->disk_name, blk); state->disk->disk_name, blk);
} }
@ -79,10 +91,15 @@ int amiga_partition(struct parsed_partitions *state)
blk = be32_to_cpu(rdb->rdb_PartitionList); blk = be32_to_cpu(rdb->rdb_PartitionList);
put_dev_sector(sect); put_dev_sector(sect);
for (part = 1; blk>0 && part<=16; part++, put_dev_sector(sect)) { for (part = 1; blk>0 && part<=16; part++, put_dev_sector(sect)) {
blk *= blksize; /* Read in terms partition table understands */ /* Read in terms partition table understands */
if (check_mul_overflow(blk, (sector_t) blksize, &blk)) {
pr_err("Dev %s: overflow calculating partition block %llu! Skipping partitions %u and beyond\n",
state->disk->disk_name, blk, part);
break;
}
data = read_part_sector(state, blk, &sect); data = read_part_sector(state, blk, &sect);
if (!data) { if (!data) {
pr_err("Dev %s: unable to read partition block %d\n", pr_err("Dev %s: unable to read partition block %llu\n",
state->disk->disk_name, blk); state->disk->disk_name, blk);
res = -1; res = -1;
goto rdb_done; goto rdb_done;
@ -94,19 +111,70 @@ int amiga_partition(struct parsed_partitions *state)
if (checksum_block((__be32 *)pb, be32_to_cpu(pb->pb_SummedLongs) & 0x7F) != 0 ) if (checksum_block((__be32 *)pb, be32_to_cpu(pb->pb_SummedLongs) & 0x7F) != 0 )
continue; continue;
/* Tell Kernel about it */ /* RDB gives us more than enough rope to hang ourselves with,
* many times over (2^128 bytes if all fields max out).
* Some careful checks are in order, so check for potential
* overflows.
* We are multiplying four 32 bit numbers to one sector_t!
*/
nr_hd = be32_to_cpu(pb->pb_Environment[NR_HD]);
nr_sect = be32_to_cpu(pb->pb_Environment[NR_SECT]);
/* CylBlocks is total number of blocks per cylinder */
if (check_mul_overflow(nr_hd, nr_sect, &cylblk)) {
pr_err("Dev %s: heads*sects %u overflows u32, skipping partition!\n",
state->disk->disk_name, cylblk);
continue;
}
/* check for consistency with RDB defined CylBlocks */
if (cylblk > be32_to_cpu(rdb->rdb_CylBlocks)) {
pr_warn("Dev %s: cylblk %u > rdb_CylBlocks %u!\n",
state->disk->disk_name, cylblk,
be32_to_cpu(rdb->rdb_CylBlocks));
}
/* RDB allows for variable logical block size -
* normalize to 512 byte blocks and check result.
*/
if (check_mul_overflow(cylblk, blksize, &cylblk)) {
pr_err("Dev %s: partition %u bytes per cyl. overflows u32, skipping partition!\n",
state->disk->disk_name, part);
continue;
}
/* Calculate partition start and end. Limit of 32 bit on cylblk
* guarantees no overflow occurs if LBD support is enabled.
*/
lo_cyl = be32_to_cpu(pb->pb_Environment[LO_CYL]);
start_sect = ((u64) lo_cyl * cylblk);
hi_cyl = be32_to_cpu(pb->pb_Environment[HI_CYL]);
nr_sects = (((u64) hi_cyl - lo_cyl + 1) * cylblk);
nr_sects = (be32_to_cpu(pb->pb_Environment[10]) + 1 -
be32_to_cpu(pb->pb_Environment[9])) *
be32_to_cpu(pb->pb_Environment[3]) *
be32_to_cpu(pb->pb_Environment[5]) *
blksize;
if (!nr_sects) if (!nr_sects)
continue; continue;
start_sect = be32_to_cpu(pb->pb_Environment[9]) *
be32_to_cpu(pb->pb_Environment[3]) * /* Warn user if partition end overflows u32 (AmigaDOS limit) */
be32_to_cpu(pb->pb_Environment[5]) *
blksize; if ((start_sect + nr_sects) > UINT_MAX) {
pr_warn("Dev %s: partition %u (%llu-%llu) needs 64 bit device support!\n",
state->disk->disk_name, part,
start_sect, start_sect + nr_sects);
}
if (check_add_overflow(start_sect, nr_sects, &end_sect)) {
pr_err("Dev %s: partition %u (%llu-%llu) needs LBD device support, skipping partition!\n",
state->disk->disk_name, part,
start_sect, end_sect);
continue;
}
/* Tell Kernel about it */
put_partition(state,slot++,start_sect,nr_sects); put_partition(state,slot++,start_sect,nr_sects);
{ {
/* Be even more informative to aid mounting */ /* Be even more informative to aid mounting */

View file

@ -12,7 +12,7 @@
#include <linux/raid/detect.h> #include <linux/raid/detect.h>
#include "check.h" #include "check.h"
static int (*check_part[])(struct parsed_partitions *) = { static int (*const check_part[])(struct parsed_partitions *) = {
/* /*
* Probe partition formats with tables at disk address 0 * Probe partition formats with tables at disk address 0
* that also have an ADFS boot block at 0xdc0. * that also have an ADFS boot block at 0xdc0.
@ -228,7 +228,7 @@ static struct attribute *part_attrs[] = {
NULL NULL
}; };
static struct attribute_group part_attr_group = { static const struct attribute_group part_attr_group = {
.attrs = part_attrs, .attrs = part_attrs,
}; };
@ -256,31 +256,36 @@ static int part_uevent(const struct device *dev, struct kobj_uevent_env *env)
return 0; return 0;
} }
struct device_type part_type = { const struct device_type part_type = {
.name = "partition", .name = "partition",
.groups = part_attr_groups, .groups = part_attr_groups,
.release = part_release, .release = part_release,
.uevent = part_uevent, .uevent = part_uevent,
}; };
static void delete_partition(struct block_device *part) void drop_partition(struct block_device *part)
{ {
lockdep_assert_held(&part->bd_disk->open_mutex); lockdep_assert_held(&part->bd_disk->open_mutex);
fsync_bdev(part);
__invalidate_device(part, true);
xa_erase(&part->bd_disk->part_tbl, part->bd_partno); xa_erase(&part->bd_disk->part_tbl, part->bd_partno);
kobject_put(part->bd_holder_dir); kobject_put(part->bd_holder_dir);
device_del(&part->bd_device);
device_del(&part->bd_device);
put_device(&part->bd_device);
}
static void delete_partition(struct block_device *part)
{
/* /*
* Remove the block device from the inode hash, so that it cannot be * Remove the block device from the inode hash, so that it cannot be
* looked up any more even when openers still hold references. * looked up any more even when openers still hold references.
*/ */
remove_inode_hash(part->bd_inode); remove_inode_hash(part->bd_inode);
put_device(&part->bd_device); fsync_bdev(part);
__invalidate_device(part, true);
drop_partition(part);
} }
static ssize_t whole_disk_show(struct device *dev, static ssize_t whole_disk_show(struct device *dev,
@ -288,7 +293,7 @@ static ssize_t whole_disk_show(struct device *dev,
{ {
return 0; return 0;
} }
static DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL); static const DEVICE_ATTR(whole_disk, 0444, whole_disk_show, NULL);
/* /*
* Must be called either with open_mutex held, before a disk can be opened or * Must be called either with open_mutex held, before a disk can be opened or
@ -436,10 +441,21 @@ static bool partition_overlaps(struct gendisk *disk, sector_t start,
int bdev_add_partition(struct gendisk *disk, int partno, sector_t start, int bdev_add_partition(struct gendisk *disk, int partno, sector_t start,
sector_t length) sector_t length)
{ {
sector_t capacity = get_capacity(disk), end;
struct block_device *part; struct block_device *part;
int ret; int ret;
mutex_lock(&disk->open_mutex); mutex_lock(&disk->open_mutex);
if (check_add_overflow(start, length, &end)) {
ret = -EINVAL;
goto out;
}
if (start >= capacity || end > capacity) {
ret = -EINVAL;
goto out;
}
if (!disk_live(disk)) { if (!disk_live(disk)) {
ret = -ENXIO; ret = -ENXIO;
goto out; goto out;
@ -519,17 +535,6 @@ static bool disk_unlock_native_capacity(struct gendisk *disk)
return true; return true;
} }
void blk_drop_partitions(struct gendisk *disk)
{
struct block_device *part;
unsigned long idx;
lockdep_assert_held(&disk->open_mutex);
xa_for_each_start(&disk->part_tbl, idx, part, 1)
delete_partition(part);
}
static bool blk_add_partition(struct gendisk *disk, static bool blk_add_partition(struct gendisk *disk,
struct parsed_partitions *state, int p) struct parsed_partitions *state, int p)
{ {
@ -646,6 +651,8 @@ out_free_state:
int bdev_disk_changed(struct gendisk *disk, bool invalidate) int bdev_disk_changed(struct gendisk *disk, bool invalidate)
{ {
struct block_device *part;
unsigned long idx;
int ret = 0; int ret = 0;
lockdep_assert_held(&disk->open_mutex); lockdep_assert_held(&disk->open_mutex);
@ -658,8 +665,9 @@ rescan:
return -EBUSY; return -EBUSY;
sync_blockdev(disk->part0); sync_blockdev(disk->part0);
invalidate_bdev(disk->part0); invalidate_bdev(disk->part0);
blk_drop_partitions(disk);
xa_for_each_start(&disk->part_tbl, idx, part, 1)
delete_partition(part);
clear_bit(GD_NEED_PART_SCAN, &disk->state); clear_bit(GD_NEED_PART_SCAN, &disk->state);
/* /*

View file

@ -751,14 +751,12 @@ static int really_probe_debug(struct device *dev, struct device_driver *drv)
* *
* Should somehow figure out how to use a semaphore, not an atomic variable... * Should somehow figure out how to use a semaphore, not an atomic variable...
*/ */
int driver_probe_done(void) bool __init driver_probe_done(void)
{ {
int local_probe_count = atomic_read(&probe_count); int local_probe_count = atomic_read(&probe_count);
pr_debug("%s: probe_count = %d\n", __func__, local_probe_count); pr_debug("%s: probe_count = %d\n", __func__, local_probe_count);
if (local_probe_count) return !local_probe_count;
return -EBUSY;
return 0;
} }
/** /**

View file

@ -1532,7 +1532,7 @@ static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0; return 0;
} }
static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, static int fd_locked_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long param) unsigned int cmd, unsigned long param)
{ {
struct amiga_floppy_struct *p = bdev->bd_disk->private_data; struct amiga_floppy_struct *p = bdev->bd_disk->private_data;
@ -1607,7 +1607,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
return 0; return 0;
} }
static int fd_ioctl(struct block_device *bdev, fmode_t mode, static int fd_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long param) unsigned int cmd, unsigned long param)
{ {
int ret; int ret;
@ -1654,10 +1654,10 @@ static void fd_probe(int dev)
* /dev/PS0 etc), and disallows simultaneous access to the same * /dev/PS0 etc), and disallows simultaneous access to the same
* drive with different device numbers. * drive with different device numbers.
*/ */
static int floppy_open(struct block_device *bdev, fmode_t mode) static int floppy_open(struct gendisk *disk, blk_mode_t mode)
{ {
int drive = MINOR(bdev->bd_dev) & 3; int drive = disk->first_minor & 3;
int system = (MINOR(bdev->bd_dev) & 4) >> 2; int system = (disk->first_minor & 4) >> 2;
int old_dev; int old_dev;
unsigned long flags; unsigned long flags;
@ -1673,10 +1673,9 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
mutex_unlock(&amiflop_mutex); mutex_unlock(&amiflop_mutex);
return -ENXIO; return -ENXIO;
} }
if (mode & (BLK_OPEN_READ | BLK_OPEN_WRITE)) {
if (mode & (FMODE_READ|FMODE_WRITE)) { disk_check_media_change(disk);
bdev_check_media_change(bdev); if (mode & BLK_OPEN_WRITE) {
if (mode & FMODE_WRITE) {
int wrprot; int wrprot;
get_fdc(drive); get_fdc(drive);
@ -1691,7 +1690,6 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
} }
} }
} }
local_irq_save(flags); local_irq_save(flags);
fd_ref[drive]++; fd_ref[drive]++;
fd_device[drive] = system; fd_device[drive] = system;
@ -1709,7 +1707,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
return 0; return 0;
} }
static void floppy_release(struct gendisk *disk, fmode_t mode) static void floppy_release(struct gendisk *disk)
{ {
struct amiga_floppy_struct *p = disk->private_data; struct amiga_floppy_struct *p = disk->private_data;
int drive = p - unit; int drive = p - unit;

View file

@ -204,9 +204,9 @@ aoedisk_rm_debugfs(struct aoedev *d)
} }
static int static int
aoeblk_open(struct block_device *bdev, fmode_t mode) aoeblk_open(struct gendisk *disk, blk_mode_t mode)
{ {
struct aoedev *d = bdev->bd_disk->private_data; struct aoedev *d = disk->private_data;
ulong flags; ulong flags;
if (!virt_addr_valid(d)) { if (!virt_addr_valid(d)) {
@ -232,7 +232,7 @@ aoeblk_open(struct block_device *bdev, fmode_t mode)
} }
static void static void
aoeblk_release(struct gendisk *disk, fmode_t mode) aoeblk_release(struct gendisk *disk)
{ {
struct aoedev *d = disk->private_data; struct aoedev *d = disk->private_data;
ulong flags; ulong flags;
@ -285,7 +285,7 @@ aoeblk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
} }
static int static int
aoeblk_ioctl(struct block_device *bdev, fmode_t mode, uint cmd, ulong arg) aoeblk_ioctl(struct block_device *bdev, blk_mode_t mode, uint cmd, ulong arg)
{ {
struct aoedev *d; struct aoedev *d;

View file

@ -49,7 +49,7 @@ static int emsgs_head_idx, emsgs_tail_idx;
static struct completion emsgs_comp; static struct completion emsgs_comp;
static spinlock_t emsgs_lock; static spinlock_t emsgs_lock;
static int nblocked_emsgs_readers; static int nblocked_emsgs_readers;
static struct class *aoe_class;
static struct aoe_chardev chardevs[] = { static struct aoe_chardev chardevs[] = {
{ MINOR_ERR, "err" }, { MINOR_ERR, "err" },
{ MINOR_DISCOVER, "discover" }, { MINOR_DISCOVER, "discover" },
@ -58,6 +58,16 @@ static struct aoe_chardev chardevs[] = {
{ MINOR_FLUSH, "flush" }, { MINOR_FLUSH, "flush" },
}; };
static char *aoe_devnode(const struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "etherd/%s", dev_name(dev));
}
static const struct class aoe_class = {
.name = "aoe",
.devnode = aoe_devnode,
};
static int static int
discover(void) discover(void)
{ {
@ -273,11 +283,6 @@ static const struct file_operations aoe_fops = {
.llseek = noop_llseek, .llseek = noop_llseek,
}; };
static char *aoe_devnode(const struct device *dev, umode_t *mode)
{
return kasprintf(GFP_KERNEL, "etherd/%s", dev_name(dev));
}
int __init int __init
aoechr_init(void) aoechr_init(void)
{ {
@ -290,15 +295,14 @@ aoechr_init(void)
} }
init_completion(&emsgs_comp); init_completion(&emsgs_comp);
spin_lock_init(&emsgs_lock); spin_lock_init(&emsgs_lock);
aoe_class = class_create("aoe"); n = class_register(&aoe_class);
if (IS_ERR(aoe_class)) { if (n) {
unregister_chrdev(AOE_MAJOR, "aoechr"); unregister_chrdev(AOE_MAJOR, "aoechr");
return PTR_ERR(aoe_class); return n;
} }
aoe_class->devnode = aoe_devnode;
for (i = 0; i < ARRAY_SIZE(chardevs); ++i) for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
device_create(aoe_class, NULL, device_create(&aoe_class, NULL,
MKDEV(AOE_MAJOR, chardevs[i].minor), NULL, MKDEV(AOE_MAJOR, chardevs[i].minor), NULL,
chardevs[i].name); chardevs[i].name);
@ -311,8 +315,8 @@ aoechr_exit(void)
int i; int i;
for (i = 0; i < ARRAY_SIZE(chardevs); ++i) for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
device_destroy(aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor)); device_destroy(&aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor));
class_destroy(aoe_class); class_unregister(&aoe_class);
unregister_chrdev(AOE_MAJOR, "aoechr"); unregister_chrdev(AOE_MAJOR, "aoechr");
} }

View file

@ -442,13 +442,13 @@ static void fd_times_out(struct timer_list *unused);
static void finish_fdc( void ); static void finish_fdc( void );
static void finish_fdc_done( int dummy ); static void finish_fdc_done( int dummy );
static void setup_req_params( int drive ); static void setup_req_params( int drive );
static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int static int fd_locked_ioctl(struct block_device *bdev, blk_mode_t mode,
cmd, unsigned long param); unsigned int cmd, unsigned long param);
static void fd_probe( int drive ); static void fd_probe( int drive );
static int fd_test_drive_present( int drive ); static int fd_test_drive_present( int drive );
static void config_types( void ); static void config_types( void );
static int floppy_open(struct block_device *bdev, fmode_t mode); static int floppy_open(struct gendisk *disk, blk_mode_t mode);
static void floppy_release(struct gendisk *disk, fmode_t mode); static void floppy_release(struct gendisk *disk);
/************************* End of Prototypes **************************/ /************************* End of Prototypes **************************/
@ -1581,7 +1581,7 @@ out:
return BLK_STS_OK; return BLK_STS_OK;
} }
static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, static int fd_locked_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long param) unsigned int cmd, unsigned long param)
{ {
struct gendisk *disk = bdev->bd_disk; struct gendisk *disk = bdev->bd_disk;
@ -1760,15 +1760,15 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode,
/* invalidate the buffer track to force a reread */ /* invalidate the buffer track to force a reread */
BufferDrive = -1; BufferDrive = -1;
set_bit(drive, &fake_change); set_bit(drive, &fake_change);
if (bdev_check_media_change(bdev)) if (disk_check_media_change(disk))
floppy_revalidate(bdev->bd_disk); floppy_revalidate(disk);
return 0; return 0;
default: default:
return -EINVAL; return -EINVAL;
} }
} }
static int fd_ioctl(struct block_device *bdev, fmode_t mode, static int fd_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
int ret; int ret;
@ -1915,32 +1915,31 @@ static void __init config_types( void )
* drive with different device numbers. * drive with different device numbers.
*/ */
static int floppy_open(struct block_device *bdev, fmode_t mode) static int floppy_open(struct gendisk *disk, blk_mode_t mode)
{ {
struct atari_floppy_struct *p = bdev->bd_disk->private_data; struct atari_floppy_struct *p = disk->private_data;
int type = MINOR(bdev->bd_dev) >> 2; int type = disk->first_minor >> 2;
DPRINT(("fd_open: type=%d\n",type)); DPRINT(("fd_open: type=%d\n",type));
if (p->ref && p->type != type) if (p->ref && p->type != type)
return -EBUSY; return -EBUSY;
if (p->ref == -1 || (p->ref && mode & FMODE_EXCL)) if (p->ref == -1 || (p->ref && mode & BLK_OPEN_EXCL))
return -EBUSY; return -EBUSY;
if (mode & BLK_OPEN_EXCL)
if (mode & FMODE_EXCL)
p->ref = -1; p->ref = -1;
else else
p->ref++; p->ref++;
p->type = type; p->type = type;
if (mode & FMODE_NDELAY) if (mode & BLK_OPEN_NDELAY)
return 0; return 0;
if (mode & (FMODE_READ|FMODE_WRITE)) { if (mode & (BLK_OPEN_READ | BLK_OPEN_WRITE)) {
if (bdev_check_media_change(bdev)) if (disk_check_media_change(disk))
floppy_revalidate(bdev->bd_disk); floppy_revalidate(disk);
if (mode & FMODE_WRITE) { if (mode & BLK_OPEN_WRITE) {
if (p->wpstat) { if (p->wpstat) {
if (p->ref < 0) if (p->ref < 0)
p->ref = 0; p->ref = 0;
@ -1953,18 +1952,18 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
return 0; return 0;
} }
static int floppy_unlocked_open(struct block_device *bdev, fmode_t mode) static int floppy_unlocked_open(struct gendisk *disk, blk_mode_t mode)
{ {
int ret; int ret;
mutex_lock(&ataflop_mutex); mutex_lock(&ataflop_mutex);
ret = floppy_open(bdev, mode); ret = floppy_open(disk, mode);
mutex_unlock(&ataflop_mutex); mutex_unlock(&ataflop_mutex);
return ret; return ret;
} }
static void floppy_release(struct gendisk *disk, fmode_t mode) static void floppy_release(struct gendisk *disk)
{ {
struct atari_floppy_struct *p = disk->private_data; struct atari_floppy_struct *p = disk->private_data;
mutex_lock(&ataflop_mutex); mutex_lock(&ataflop_mutex);

View file

@ -19,7 +19,7 @@
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/radix-tree.h> #include <linux/xarray.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
@ -28,7 +28,7 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
/* /*
* Each block ramdisk device has a radix_tree brd_pages of pages that stores * Each block ramdisk device has a xarray brd_pages of pages that stores
* the pages containing the block device's contents. A brd page's ->index is * the pages containing the block device's contents. A brd page's ->index is
* its offset in PAGE_SIZE units. This is similar to, but in no way connected * its offset in PAGE_SIZE units. This is similar to, but in no way connected
* with, the kernel's pagecache or buffer cache (which sit above our block * with, the kernel's pagecache or buffer cache (which sit above our block
@ -40,11 +40,9 @@ struct brd_device {
struct list_head brd_list; struct list_head brd_list;
/* /*
* Backing store of pages and lock to protect it. This is the contents * Backing store of pages. This is the contents of the block device.
* of the block device.
*/ */
spinlock_t brd_lock; struct xarray brd_pages;
struct radix_tree_root brd_pages;
u64 brd_nr_pages; u64 brd_nr_pages;
}; };
@ -56,21 +54,8 @@ static struct page *brd_lookup_page(struct brd_device *brd, sector_t sector)
pgoff_t idx; pgoff_t idx;
struct page *page; struct page *page;
/*
* The page lifetime is protected by the fact that we have opened the
* device node -- brd pages will never be deleted under us, so we
* don't need any further locking or refcounting.
*
* This is strictly true for the radix-tree nodes as well (ie. we
* don't actually need the rcu_read_lock()), however that is not a
* documented feature of the radix-tree API so it is better to be
* safe here (we don't have total exclusion from radix tree updates
* here, only deletes).
*/
rcu_read_lock();
idx = sector >> PAGE_SECTORS_SHIFT; /* sector to page index */ idx = sector >> PAGE_SECTORS_SHIFT; /* sector to page index */
page = radix_tree_lookup(&brd->brd_pages, idx); page = xa_load(&brd->brd_pages, idx);
rcu_read_unlock();
BUG_ON(page && page->index != idx); BUG_ON(page && page->index != idx);
@ -83,7 +68,7 @@ static struct page *brd_lookup_page(struct brd_device *brd, sector_t sector)
static int brd_insert_page(struct brd_device *brd, sector_t sector, gfp_t gfp) static int brd_insert_page(struct brd_device *brd, sector_t sector, gfp_t gfp)
{ {
pgoff_t idx; pgoff_t idx;
struct page *page; struct page *page, *cur;
int ret = 0; int ret = 0;
page = brd_lookup_page(brd, sector); page = brd_lookup_page(brd, sector);
@ -94,71 +79,42 @@ static int brd_insert_page(struct brd_device *brd, sector_t sector, gfp_t gfp)
if (!page) if (!page)
return -ENOMEM; return -ENOMEM;
if (radix_tree_maybe_preload(gfp)) { xa_lock(&brd->brd_pages);
__free_page(page);
return -ENOMEM;
}
spin_lock(&brd->brd_lock);
idx = sector >> PAGE_SECTORS_SHIFT; idx = sector >> PAGE_SECTORS_SHIFT;
page->index = idx; page->index = idx;
if (radix_tree_insert(&brd->brd_pages, idx, page)) {
cur = __xa_cmpxchg(&brd->brd_pages, idx, NULL, page, gfp);
if (unlikely(cur)) {
__free_page(page); __free_page(page);
page = radix_tree_lookup(&brd->brd_pages, idx); ret = xa_err(cur);
if (!page) if (!ret && (cur->index != idx))
ret = -ENOMEM;
else if (page->index != idx)
ret = -EIO; ret = -EIO;
} else { } else {
brd->brd_nr_pages++; brd->brd_nr_pages++;
} }
spin_unlock(&brd->brd_lock);
radix_tree_preload_end(); xa_unlock(&brd->brd_pages);
return ret; return ret;
} }
/* /*
* Free all backing store pages and radix tree. This must only be called when * Free all backing store pages and xarray. This must only be called when
* there are no other users of the device. * there are no other users of the device.
*/ */
#define FREE_BATCH 16
static void brd_free_pages(struct brd_device *brd) static void brd_free_pages(struct brd_device *brd)
{ {
unsigned long pos = 0; struct page *page;
struct page *pages[FREE_BATCH]; pgoff_t idx;
int nr_pages;
do { xa_for_each(&brd->brd_pages, idx, page) {
int i; __free_page(page);
nr_pages = radix_tree_gang_lookup(&brd->brd_pages,
(void **)pages, pos, FREE_BATCH);
for (i = 0; i < nr_pages; i++) {
void *ret;
BUG_ON(pages[i]->index < pos);
pos = pages[i]->index;
ret = radix_tree_delete(&brd->brd_pages, pos);
BUG_ON(!ret || ret != pages[i]);
__free_page(pages[i]);
}
pos++;
/*
* It takes 3.4 seconds to remove 80GiB ramdisk.
* So, we need cond_resched to avoid stalling the CPU.
*/
cond_resched(); cond_resched();
}
/* xa_destroy(&brd->brd_pages);
* This assumes radix_tree_gang_lookup always returns as
* many pages as possible. If the radix-tree code changes,
* so will this have to.
*/
} while (nr_pages == FREE_BATCH);
} }
/* /*
@ -372,8 +328,7 @@ static int brd_alloc(int i)
brd->brd_number = i; brd->brd_number = i;
list_add_tail(&brd->brd_list, &brd_devices); list_add_tail(&brd->brd_list, &brd_devices);
spin_lock_init(&brd->brd_lock); xa_init(&brd->brd_pages);
INIT_RADIX_TREE(&brd->brd_pages, GFP_ATOMIC);
snprintf(buf, DISK_NAME_LEN, "ram%d", i); snprintf(buf, DISK_NAME_LEN, "ram%d", i);
if (!IS_ERR_OR_NULL(brd_debugfs_dir)) if (!IS_ERR_OR_NULL(brd_debugfs_dir))

View file

@ -1043,9 +1043,7 @@ static void bm_page_io_async(struct drbd_bm_aio_ctx *ctx, int page_nr) __must_ho
bio = bio_alloc_bioset(device->ldev->md_bdev, 1, op, GFP_NOIO, bio = bio_alloc_bioset(device->ldev->md_bdev, 1, op, GFP_NOIO,
&drbd_md_io_bio_set); &drbd_md_io_bio_set);
bio->bi_iter.bi_sector = on_disk_sector; bio->bi_iter.bi_sector = on_disk_sector;
/* bio_add_page of a single page to an empty bio will always succeed, __bio_add_page(bio, page, len, 0);
* according to api. Do we want to assert that? */
bio_add_page(bio, page, len, 0);
bio->bi_private = ctx; bio->bi_private = ctx;
bio->bi_end_io = drbd_bm_endio; bio->bi_end_io = drbd_bm_endio;

View file

@ -37,7 +37,6 @@
#include <linux/notifier.h> #include <linux/notifier.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h> #include <linux/unistd.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
@ -50,8 +49,8 @@
#include "drbd_debugfs.h" #include "drbd_debugfs.h"
static DEFINE_MUTEX(drbd_main_mutex); static DEFINE_MUTEX(drbd_main_mutex);
static int drbd_open(struct block_device *bdev, fmode_t mode); static int drbd_open(struct gendisk *disk, blk_mode_t mode);
static void drbd_release(struct gendisk *gd, fmode_t mode); static void drbd_release(struct gendisk *gd);
static void md_sync_timer_fn(struct timer_list *t); static void md_sync_timer_fn(struct timer_list *t);
static int w_bitmap_io(struct drbd_work *w, int unused); static int w_bitmap_io(struct drbd_work *w, int unused);
@ -1883,9 +1882,9 @@ int drbd_send_all(struct drbd_connection *connection, struct socket *sock, void
return 0; return 0;
} }
static int drbd_open(struct block_device *bdev, fmode_t mode) static int drbd_open(struct gendisk *disk, blk_mode_t mode)
{ {
struct drbd_device *device = bdev->bd_disk->private_data; struct drbd_device *device = disk->private_data;
unsigned long flags; unsigned long flags;
int rv = 0; int rv = 0;
@ -1895,7 +1894,7 @@ static int drbd_open(struct block_device *bdev, fmode_t mode)
* and no race with updating open_cnt */ * and no race with updating open_cnt */
if (device->state.role != R_PRIMARY) { if (device->state.role != R_PRIMARY) {
if (mode & FMODE_WRITE) if (mode & BLK_OPEN_WRITE)
rv = -EROFS; rv = -EROFS;
else if (!drbd_allow_oos) else if (!drbd_allow_oos)
rv = -EMEDIUMTYPE; rv = -EMEDIUMTYPE;
@ -1909,9 +1908,10 @@ static int drbd_open(struct block_device *bdev, fmode_t mode)
return rv; return rv;
} }
static void drbd_release(struct gendisk *gd, fmode_t mode) static void drbd_release(struct gendisk *gd)
{ {
struct drbd_device *device = gd->private_data; struct drbd_device *device = gd->private_data;
mutex_lock(&drbd_main_mutex); mutex_lock(&drbd_main_mutex);
device->open_cnt--; device->open_cnt--;
mutex_unlock(&drbd_main_mutex); mutex_unlock(&drbd_main_mutex);

View file

@ -1640,8 +1640,8 @@ static struct block_device *open_backing_dev(struct drbd_device *device,
struct block_device *bdev; struct block_device *bdev;
int err = 0; int err = 0;
bdev = blkdev_get_by_path(bdev_path, bdev = blkdev_get_by_path(bdev_path, BLK_OPEN_READ | BLK_OPEN_WRITE,
FMODE_READ | FMODE_WRITE | FMODE_EXCL, claim_ptr); claim_ptr, NULL);
if (IS_ERR(bdev)) { if (IS_ERR(bdev)) {
drbd_err(device, "open(\"%s\") failed with %ld\n", drbd_err(device, "open(\"%s\") failed with %ld\n",
bdev_path, PTR_ERR(bdev)); bdev_path, PTR_ERR(bdev));
@ -1653,7 +1653,7 @@ static struct block_device *open_backing_dev(struct drbd_device *device,
err = bd_link_disk_holder(bdev, device->vdisk); err = bd_link_disk_holder(bdev, device->vdisk);
if (err) { if (err) {
blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); blkdev_put(bdev, claim_ptr);
drbd_err(device, "bd_link_disk_holder(\"%s\", ...) failed with %d\n", drbd_err(device, "bd_link_disk_holder(\"%s\", ...) failed with %d\n",
bdev_path, err); bdev_path, err);
bdev = ERR_PTR(err); bdev = ERR_PTR(err);
@ -1695,13 +1695,13 @@ static int open_backing_devices(struct drbd_device *device,
} }
static void close_backing_dev(struct drbd_device *device, struct block_device *bdev, static void close_backing_dev(struct drbd_device *device, struct block_device *bdev,
bool do_bd_unlink) void *claim_ptr, bool do_bd_unlink)
{ {
if (!bdev) if (!bdev)
return; return;
if (do_bd_unlink) if (do_bd_unlink)
bd_unlink_disk_holder(bdev, device->vdisk); bd_unlink_disk_holder(bdev, device->vdisk);
blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); blkdev_put(bdev, claim_ptr);
} }
void drbd_backing_dev_free(struct drbd_device *device, struct drbd_backing_dev *ldev) void drbd_backing_dev_free(struct drbd_device *device, struct drbd_backing_dev *ldev)
@ -1709,8 +1709,11 @@ void drbd_backing_dev_free(struct drbd_device *device, struct drbd_backing_dev *
if (ldev == NULL) if (ldev == NULL)
return; return;
close_backing_dev(device, ldev->md_bdev, ldev->md_bdev != ldev->backing_bdev); close_backing_dev(device, ldev->md_bdev,
close_backing_dev(device, ldev->backing_bdev, true); ldev->md.meta_dev_idx < 0 ?
(void *)device : (void *)drbd_m_holder,
ldev->md_bdev != ldev->backing_bdev);
close_backing_dev(device, ldev->backing_bdev, device, true);
kfree(ldev->disk_conf); kfree(ldev->disk_conf);
kfree(ldev); kfree(ldev);
@ -2126,8 +2129,11 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info)
fail: fail:
conn_reconfig_done(connection); conn_reconfig_done(connection);
if (nbc) { if (nbc) {
close_backing_dev(device, nbc->md_bdev, nbc->md_bdev != nbc->backing_bdev); close_backing_dev(device, nbc->md_bdev,
close_backing_dev(device, nbc->backing_bdev, true); nbc->disk_conf->meta_dev_idx < 0 ?
(void *)device : (void *)drbd_m_holder,
nbc->md_bdev != nbc->backing_bdev);
close_backing_dev(device, nbc->backing_bdev, device, true);
kfree(nbc); kfree(nbc);
} }
kfree(new_disk_conf); kfree(new_disk_conf);

View file

@ -27,7 +27,6 @@
#include <uapi/linux/sched/types.h> #include <uapi/linux/sched/types.h>
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
#include <linux/pkt_sched.h> #include <linux/pkt_sched.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h> #include <linux/unistd.h>
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/random.h> #include <linux/random.h>

View file

@ -402,7 +402,7 @@ static struct floppy_drive_struct drive_state[N_DRIVE];
static struct floppy_write_errors write_errors[N_DRIVE]; static struct floppy_write_errors write_errors[N_DRIVE];
static struct timer_list motor_off_timer[N_DRIVE]; static struct timer_list motor_off_timer[N_DRIVE];
static struct blk_mq_tag_set tag_sets[N_DRIVE]; static struct blk_mq_tag_set tag_sets[N_DRIVE];
static struct block_device *opened_bdev[N_DRIVE]; static struct gendisk *opened_disk[N_DRIVE];
static DEFINE_MUTEX(open_lock); static DEFINE_MUTEX(open_lock);
static struct floppy_raw_cmd *raw_cmd, default_raw_cmd; static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;
@ -3210,13 +3210,13 @@ static int floppy_raw_cmd_ioctl(int type, int drive, int cmd,
#endif #endif
static int invalidate_drive(struct block_device *bdev) static int invalidate_drive(struct gendisk *disk)
{ {
/* invalidate the buffer track to force a reread */ /* invalidate the buffer track to force a reread */
set_bit((long)bdev->bd_disk->private_data, &fake_change); set_bit((long)disk->private_data, &fake_change);
process_fd_request(); process_fd_request();
if (bdev_check_media_change(bdev)) if (disk_check_media_change(disk))
floppy_revalidate(bdev->bd_disk); floppy_revalidate(disk);
return 0; return 0;
} }
@ -3251,10 +3251,11 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
floppy_type[type].size + 1; floppy_type[type].size + 1;
process_fd_request(); process_fd_request();
for (cnt = 0; cnt < N_DRIVE; cnt++) { for (cnt = 0; cnt < N_DRIVE; cnt++) {
struct block_device *bdev = opened_bdev[cnt]; struct gendisk *disk = opened_disk[cnt];
if (!bdev || ITYPE(drive_state[cnt].fd_device) != type)
if (!disk || ITYPE(drive_state[cnt].fd_device) != type)
continue; continue;
__invalidate_device(bdev, true); __invalidate_device(disk->part0, true);
} }
mutex_unlock(&open_lock); mutex_unlock(&open_lock);
} else { } else {
@ -3287,7 +3288,7 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g,
drive_state[current_drive].maxtrack || drive_state[current_drive].maxtrack ||
((user_params[drive].sect ^ oldStretch) & ((user_params[drive].sect ^ oldStretch) &
(FD_SWAPSIDES | FD_SECTBASEMASK))) (FD_SWAPSIDES | FD_SECTBASEMASK)))
invalidate_drive(bdev); invalidate_drive(bdev->bd_disk);
else else
process_fd_request(); process_fd_request();
} }
@ -3393,8 +3394,8 @@ static bool valid_floppy_drive_params(const short autodetect[FD_AUTODETECT_SIZE]
return true; return true;
} }
static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, static int fd_locked_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned long param) unsigned int cmd, unsigned long param)
{ {
int drive = (long)bdev->bd_disk->private_data; int drive = (long)bdev->bd_disk->private_data;
int type = ITYPE(drive_state[drive].fd_device); int type = ITYPE(drive_state[drive].fd_device);
@ -3427,7 +3428,8 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
return ret; return ret;
/* permission checks */ /* permission checks */
if (((cmd & 0x40) && !(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) || if (((cmd & 0x40) &&
!(mode & (BLK_OPEN_WRITE | BLK_OPEN_WRITE_IOCTL))) ||
((cmd & 0x80) && !capable(CAP_SYS_ADMIN))) ((cmd & 0x80) && !capable(CAP_SYS_ADMIN)))
return -EPERM; return -EPERM;
@ -3464,7 +3466,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
current_type[drive] = NULL; current_type[drive] = NULL;
floppy_sizes[drive] = MAX_DISK_SIZE << 1; floppy_sizes[drive] = MAX_DISK_SIZE << 1;
drive_state[drive].keep_data = 0; drive_state[drive].keep_data = 0;
return invalidate_drive(bdev); return invalidate_drive(bdev->bd_disk);
case FDSETPRM: case FDSETPRM:
case FDDEFPRM: case FDDEFPRM:
return set_geometry(cmd, &inparam.g, drive, type, bdev); return set_geometry(cmd, &inparam.g, drive, type, bdev);
@ -3503,7 +3505,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
case FDFLUSH: case FDFLUSH:
if (lock_fdc(drive)) if (lock_fdc(drive))
return -EINTR; return -EINTR;
return invalidate_drive(bdev); return invalidate_drive(bdev->bd_disk);
case FDSETEMSGTRESH: case FDSETEMSGTRESH:
drive_params[drive].max_errors.reporting = (unsigned short)(param & 0x0f); drive_params[drive].max_errors.reporting = (unsigned short)(param & 0x0f);
return 0; return 0;
@ -3565,7 +3567,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
return 0; return 0;
} }
static int fd_ioctl(struct block_device *bdev, fmode_t mode, static int fd_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long param) unsigned int cmd, unsigned long param)
{ {
int ret; int ret;
@ -3653,8 +3655,8 @@ struct compat_floppy_write_errors {
#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state) #define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state)
#define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors) #define FDWERRORGET32 _IOR(2, 0x17, struct compat_floppy_write_errors)
static int compat_set_geometry(struct block_device *bdev, fmode_t mode, unsigned int cmd, static int compat_set_geometry(struct block_device *bdev, blk_mode_t mode,
struct compat_floppy_struct __user *arg) unsigned int cmd, struct compat_floppy_struct __user *arg)
{ {
struct floppy_struct v; struct floppy_struct v;
int drive, type; int drive, type;
@ -3663,7 +3665,7 @@ static int compat_set_geometry(struct block_device *bdev, fmode_t mode, unsigned
BUILD_BUG_ON(offsetof(struct floppy_struct, name) != BUILD_BUG_ON(offsetof(struct floppy_struct, name) !=
offsetof(struct compat_floppy_struct, name)); offsetof(struct compat_floppy_struct, name));
if (!(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) if (!(mode & (BLK_OPEN_WRITE | BLK_OPEN_WRITE_IOCTL)))
return -EPERM; return -EPERM;
memset(&v, 0, sizeof(struct floppy_struct)); memset(&v, 0, sizeof(struct floppy_struct));
@ -3860,8 +3862,8 @@ static int compat_werrorget(int drive,
return 0; return 0;
} }
static int fd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, static int fd_compat_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned long param) unsigned int cmd, unsigned long param)
{ {
int drive = (long)bdev->bd_disk->private_data; int drive = (long)bdev->bd_disk->private_data;
switch (cmd) { switch (cmd) {
@ -3962,7 +3964,7 @@ static void __init config_types(void)
pr_cont("\n"); pr_cont("\n");
} }
static void floppy_release(struct gendisk *disk, fmode_t mode) static void floppy_release(struct gendisk *disk)
{ {
int drive = (long)disk->private_data; int drive = (long)disk->private_data;
@ -3973,7 +3975,7 @@ static void floppy_release(struct gendisk *disk, fmode_t mode)
drive_state[drive].fd_ref = 0; drive_state[drive].fd_ref = 0;
} }
if (!drive_state[drive].fd_ref) if (!drive_state[drive].fd_ref)
opened_bdev[drive] = NULL; opened_disk[drive] = NULL;
mutex_unlock(&open_lock); mutex_unlock(&open_lock);
mutex_unlock(&floppy_mutex); mutex_unlock(&floppy_mutex);
} }
@ -3983,9 +3985,9 @@ static void floppy_release(struct gendisk *disk, fmode_t mode)
* /dev/PS0 etc), and disallows simultaneous access to the same * /dev/PS0 etc), and disallows simultaneous access to the same
* drive with different device numbers. * drive with different device numbers.
*/ */
static int floppy_open(struct block_device *bdev, fmode_t mode) static int floppy_open(struct gendisk *disk, blk_mode_t mode)
{ {
int drive = (long)bdev->bd_disk->private_data; int drive = (long)disk->private_data;
int old_dev, new_dev; int old_dev, new_dev;
int try; int try;
int res = -EBUSY; int res = -EBUSY;
@ -3994,7 +3996,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
mutex_lock(&floppy_mutex); mutex_lock(&floppy_mutex);
mutex_lock(&open_lock); mutex_lock(&open_lock);
old_dev = drive_state[drive].fd_device; old_dev = drive_state[drive].fd_device;
if (opened_bdev[drive] && opened_bdev[drive] != bdev) if (opened_disk[drive] && opened_disk[drive] != disk)
goto out2; goto out2;
if (!drive_state[drive].fd_ref && (drive_params[drive].flags & FD_BROKEN_DCL)) { if (!drive_state[drive].fd_ref && (drive_params[drive].flags & FD_BROKEN_DCL)) {
@ -4004,7 +4006,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
drive_state[drive].fd_ref++; drive_state[drive].fd_ref++;
opened_bdev[drive] = bdev; opened_disk[drive] = disk;
res = -ENXIO; res = -ENXIO;
@ -4038,7 +4040,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
} }
} }
new_dev = MINOR(bdev->bd_dev); new_dev = disk->first_minor;
drive_state[drive].fd_device = new_dev; drive_state[drive].fd_device = new_dev;
set_capacity(disks[drive][ITYPE(new_dev)], floppy_sizes[new_dev]); set_capacity(disks[drive][ITYPE(new_dev)], floppy_sizes[new_dev]);
if (old_dev != -1 && old_dev != new_dev) { if (old_dev != -1 && old_dev != new_dev) {
@ -4048,21 +4050,20 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
if (fdc_state[FDC(drive)].rawcmd == 1) if (fdc_state[FDC(drive)].rawcmd == 1)
fdc_state[FDC(drive)].rawcmd = 2; fdc_state[FDC(drive)].rawcmd = 2;
if (!(mode & BLK_OPEN_NDELAY)) {
if (!(mode & FMODE_NDELAY)) { if (mode & (BLK_OPEN_READ | BLK_OPEN_WRITE)) {
if (mode & (FMODE_READ|FMODE_WRITE)) {
drive_state[drive].last_checked = 0; drive_state[drive].last_checked = 0;
clear_bit(FD_OPEN_SHOULD_FAIL_BIT, clear_bit(FD_OPEN_SHOULD_FAIL_BIT,
&drive_state[drive].flags); &drive_state[drive].flags);
if (bdev_check_media_change(bdev)) if (disk_check_media_change(disk))
floppy_revalidate(bdev->bd_disk); floppy_revalidate(disk);
if (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags)) if (test_bit(FD_DISK_CHANGED_BIT, &drive_state[drive].flags))
goto out; goto out;
if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &drive_state[drive].flags)) if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &drive_state[drive].flags))
goto out; goto out;
} }
res = -EROFS; res = -EROFS;
if ((mode & FMODE_WRITE) && if ((mode & BLK_OPEN_WRITE) &&
!test_bit(FD_DISK_WRITABLE_BIT, &drive_state[drive].flags)) !test_bit(FD_DISK_WRITABLE_BIT, &drive_state[drive].flags))
goto out; goto out;
} }
@ -4073,7 +4074,7 @@ out:
drive_state[drive].fd_ref--; drive_state[drive].fd_ref--;
if (!drive_state[drive].fd_ref) if (!drive_state[drive].fd_ref)
opened_bdev[drive] = NULL; opened_disk[drive] = NULL;
out2: out2:
mutex_unlock(&open_lock); mutex_unlock(&open_lock);
mutex_unlock(&floppy_mutex); mutex_unlock(&floppy_mutex);
@ -4147,7 +4148,7 @@ static int __floppy_read_block_0(struct block_device *bdev, int drive)
cbdata.drive = drive; cbdata.drive = drive;
bio_init(&bio, bdev, &bio_vec, 1, REQ_OP_READ); bio_init(&bio, bdev, &bio_vec, 1, REQ_OP_READ);
bio_add_page(&bio, page, block_size(bdev), 0); __bio_add_page(&bio, page, block_size(bdev), 0);
bio.bi_iter.bi_sector = 0; bio.bi_iter.bi_sector = 0;
bio.bi_flags |= (1 << BIO_QUIET); bio.bi_flags |= (1 << BIO_QUIET);
@ -4203,7 +4204,8 @@ static int floppy_revalidate(struct gendisk *disk)
drive_state[drive].generation++; drive_state[drive].generation++;
if (drive_no_geom(drive)) { if (drive_no_geom(drive)) {
/* auto-sensing */ /* auto-sensing */
res = __floppy_read_block_0(opened_bdev[drive], drive); res = __floppy_read_block_0(opened_disk[drive]->part0,
drive);
} else { } else {
if (cf) if (cf)
poll_drive(false, FD_RAW_NEED_DISK); poll_drive(false, FD_RAW_NEED_DISK);

View file

@ -990,7 +990,7 @@ loop_set_status_from_info(struct loop_device *lo,
return 0; return 0;
} }
static int loop_configure(struct loop_device *lo, fmode_t mode, static int loop_configure(struct loop_device *lo, blk_mode_t mode,
struct block_device *bdev, struct block_device *bdev,
const struct loop_config *config) const struct loop_config *config)
{ {
@ -1014,8 +1014,8 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
* If we don't hold exclusive handle for the device, upgrade to it * If we don't hold exclusive handle for the device, upgrade to it
* here to avoid changing device under exclusive owner. * here to avoid changing device under exclusive owner.
*/ */
if (!(mode & FMODE_EXCL)) { if (!(mode & BLK_OPEN_EXCL)) {
error = bd_prepare_to_claim(bdev, loop_configure); error = bd_prepare_to_claim(bdev, loop_configure, NULL);
if (error) if (error)
goto out_putf; goto out_putf;
} }
@ -1050,7 +1050,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
if (error) if (error)
goto out_unlock; goto out_unlock;
if (!(file->f_mode & FMODE_WRITE) || !(mode & FMODE_WRITE) || if (!(file->f_mode & FMODE_WRITE) || !(mode & BLK_OPEN_WRITE) ||
!file->f_op->write_iter) !file->f_op->write_iter)
lo->lo_flags |= LO_FLAGS_READ_ONLY; lo->lo_flags |= LO_FLAGS_READ_ONLY;
@ -1116,7 +1116,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
if (partscan) if (partscan)
loop_reread_partitions(lo); loop_reread_partitions(lo);
if (!(mode & FMODE_EXCL)) if (!(mode & BLK_OPEN_EXCL))
bd_abort_claiming(bdev, loop_configure); bd_abort_claiming(bdev, loop_configure);
return 0; return 0;
@ -1124,7 +1124,7 @@ static int loop_configure(struct loop_device *lo, fmode_t mode,
out_unlock: out_unlock:
loop_global_unlock(lo, is_loop); loop_global_unlock(lo, is_loop);
out_bdev: out_bdev:
if (!(mode & FMODE_EXCL)) if (!(mode & BLK_OPEN_EXCL))
bd_abort_claiming(bdev, loop_configure); bd_abort_claiming(bdev, loop_configure);
out_putf: out_putf:
fput(file); fput(file);
@ -1528,7 +1528,7 @@ static int lo_simple_ioctl(struct loop_device *lo, unsigned int cmd,
return err; return err;
} }
static int lo_ioctl(struct block_device *bdev, fmode_t mode, static int lo_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
struct loop_device *lo = bdev->bd_disk->private_data; struct loop_device *lo = bdev->bd_disk->private_data;
@ -1563,24 +1563,22 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
return loop_clr_fd(lo); return loop_clr_fd(lo);
case LOOP_SET_STATUS: case LOOP_SET_STATUS:
err = -EPERM; err = -EPERM;
if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) { if ((mode & BLK_OPEN_WRITE) || capable(CAP_SYS_ADMIN))
err = loop_set_status_old(lo, argp); err = loop_set_status_old(lo, argp);
}
break; break;
case LOOP_GET_STATUS: case LOOP_GET_STATUS:
return loop_get_status_old(lo, argp); return loop_get_status_old(lo, argp);
case LOOP_SET_STATUS64: case LOOP_SET_STATUS64:
err = -EPERM; err = -EPERM;
if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN)) { if ((mode & BLK_OPEN_WRITE) || capable(CAP_SYS_ADMIN))
err = loop_set_status64(lo, argp); err = loop_set_status64(lo, argp);
}
break; break;
case LOOP_GET_STATUS64: case LOOP_GET_STATUS64:
return loop_get_status64(lo, argp); return loop_get_status64(lo, argp);
case LOOP_SET_CAPACITY: case LOOP_SET_CAPACITY:
case LOOP_SET_DIRECT_IO: case LOOP_SET_DIRECT_IO:
case LOOP_SET_BLOCK_SIZE: case LOOP_SET_BLOCK_SIZE:
if (!(mode & FMODE_WRITE) && !capable(CAP_SYS_ADMIN)) if (!(mode & BLK_OPEN_WRITE) && !capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
fallthrough; fallthrough;
default: default:
@ -1691,7 +1689,7 @@ loop_get_status_compat(struct loop_device *lo,
return err; return err;
} }
static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode, static int lo_compat_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
struct loop_device *lo = bdev->bd_disk->private_data; struct loop_device *lo = bdev->bd_disk->private_data;
@ -1727,7 +1725,7 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode,
} }
#endif #endif
static void lo_release(struct gendisk *disk, fmode_t mode) static void lo_release(struct gendisk *disk)
{ {
struct loop_device *lo = disk->private_data; struct loop_device *lo = disk->private_data;

View file

@ -3041,7 +3041,7 @@ static int rssd_disk_name_format(char *prefix,
* structure pointer. * structure pointer.
*/ */
static int mtip_block_ioctl(struct block_device *dev, static int mtip_block_ioctl(struct block_device *dev,
fmode_t mode, blk_mode_t mode,
unsigned cmd, unsigned cmd,
unsigned long arg) unsigned long arg)
{ {
@ -3079,7 +3079,7 @@ static int mtip_block_ioctl(struct block_device *dev,
* structure pointer. * structure pointer.
*/ */
static int mtip_block_compat_ioctl(struct block_device *dev, static int mtip_block_compat_ioctl(struct block_device *dev,
fmode_t mode, blk_mode_t mode,
unsigned cmd, unsigned cmd,
unsigned long arg) unsigned long arg)
{ {

View file

@ -1502,7 +1502,7 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *nbd,
return -ENOTTY; return -ENOTTY;
} }
static int nbd_ioctl(struct block_device *bdev, fmode_t mode, static int nbd_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
struct nbd_device *nbd = bdev->bd_disk->private_data; struct nbd_device *nbd = bdev->bd_disk->private_data;
@ -1553,13 +1553,13 @@ static struct nbd_config *nbd_alloc_config(void)
return config; return config;
} }
static int nbd_open(struct block_device *bdev, fmode_t mode) static int nbd_open(struct gendisk *disk, blk_mode_t mode)
{ {
struct nbd_device *nbd; struct nbd_device *nbd;
int ret = 0; int ret = 0;
mutex_lock(&nbd_index_mutex); mutex_lock(&nbd_index_mutex);
nbd = bdev->bd_disk->private_data; nbd = disk->private_data;
if (!nbd) { if (!nbd) {
ret = -ENXIO; ret = -ENXIO;
goto out; goto out;
@ -1587,17 +1587,17 @@ static int nbd_open(struct block_device *bdev, fmode_t mode)
refcount_inc(&nbd->refs); refcount_inc(&nbd->refs);
mutex_unlock(&nbd->config_lock); mutex_unlock(&nbd->config_lock);
if (max_part) if (max_part)
set_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state); set_bit(GD_NEED_PART_SCAN, &disk->state);
} else if (nbd_disconnected(nbd->config)) { } else if (nbd_disconnected(nbd->config)) {
if (max_part) if (max_part)
set_bit(GD_NEED_PART_SCAN, &bdev->bd_disk->state); set_bit(GD_NEED_PART_SCAN, &disk->state);
} }
out: out:
mutex_unlock(&nbd_index_mutex); mutex_unlock(&nbd_index_mutex);
return ret; return ret;
} }
static void nbd_release(struct gendisk *disk, fmode_t mode) static void nbd_release(struct gendisk *disk)
{ {
struct nbd_device *nbd = disk->private_data; struct nbd_device *nbd = disk->private_data;
@ -1776,7 +1776,8 @@ static struct nbd_device *nbd_dev_add(int index, unsigned int refs)
if (err == -ENOSPC) if (err == -ENOSPC)
err = -EEXIST; err = -EEXIST;
} else { } else {
err = idr_alloc(&nbd_index_idr, nbd, 0, 0, GFP_KERNEL); err = idr_alloc(&nbd_index_idr, nbd, 0,
(MINORMASK >> part_shift) + 1, GFP_KERNEL);
if (err >= 0) if (err >= 0)
index = err; index = err;
} }

File diff suppressed because it is too large Load diff

View file

@ -660,9 +660,9 @@ static bool pending_result_dec(struct pending_result *pending, int *result)
return true; return true;
} }
static int rbd_open(struct block_device *bdev, fmode_t mode) static int rbd_open(struct gendisk *disk, blk_mode_t mode)
{ {
struct rbd_device *rbd_dev = bdev->bd_disk->private_data; struct rbd_device *rbd_dev = disk->private_data;
bool removing = false; bool removing = false;
spin_lock_irq(&rbd_dev->lock); spin_lock_irq(&rbd_dev->lock);
@ -679,7 +679,7 @@ static int rbd_open(struct block_device *bdev, fmode_t mode)
return 0; return 0;
} }
static void rbd_release(struct gendisk *disk, fmode_t mode) static void rbd_release(struct gendisk *disk)
{ {
struct rbd_device *rbd_dev = disk->private_data; struct rbd_device *rbd_dev = disk->private_data;
unsigned long open_count_before; unsigned long open_count_before;

View file

@ -3,13 +3,11 @@
ccflags-y := -I$(srctree)/drivers/infiniband/ulp/rtrs ccflags-y := -I$(srctree)/drivers/infiniband/ulp/rtrs
rnbd-client-y := rnbd-clt.o \ rnbd-client-y := rnbd-clt.o \
rnbd-clt-sysfs.o \ rnbd-clt-sysfs.o
rnbd-common.o
CFLAGS_rnbd-srv-trace.o = -I$(src) CFLAGS_rnbd-srv-trace.o = -I$(src)
rnbd-server-y := rnbd-common.o \ rnbd-server-y := rnbd-srv.o \
rnbd-srv.o \
rnbd-srv-sysfs.o \ rnbd-srv-sysfs.o \
rnbd-srv-trace.o rnbd-srv-trace.o

View file

@ -24,7 +24,9 @@
#include "rnbd-clt.h" #include "rnbd-clt.h"
static struct device *rnbd_dev; static struct device *rnbd_dev;
static struct class *rnbd_dev_class; static const struct class rnbd_dev_class = {
.name = "rnbd_client",
};
static struct kobject *rnbd_devs_kobj; static struct kobject *rnbd_devs_kobj;
enum { enum {
@ -278,7 +280,7 @@ static ssize_t access_mode_show(struct kobject *kobj,
dev = container_of(kobj, struct rnbd_clt_dev, kobj); dev = container_of(kobj, struct rnbd_clt_dev, kobj);
return sysfs_emit(page, "%s\n", rnbd_access_mode_str(dev->access_mode)); return sysfs_emit(page, "%s\n", rnbd_access_modes[dev->access_mode].str);
} }
static struct kobj_attribute rnbd_clt_access_mode = static struct kobj_attribute rnbd_clt_access_mode =
@ -596,7 +598,7 @@ static ssize_t rnbd_clt_map_device_store(struct kobject *kobj,
pr_info("Mapping device %s on session %s, (access_mode: %s, nr_poll_queues: %d)\n", pr_info("Mapping device %s on session %s, (access_mode: %s, nr_poll_queues: %d)\n",
pathname, sessname, pathname, sessname,
rnbd_access_mode_str(access_mode), rnbd_access_modes[access_mode].str,
nr_poll_queues); nr_poll_queues);
dev = rnbd_clt_map_device(sessname, paths, path_cnt, port_nr, pathname, dev = rnbd_clt_map_device(sessname, paths, path_cnt, port_nr, pathname,
@ -646,11 +648,11 @@ int rnbd_clt_create_sysfs_files(void)
{ {
int err; int err;
rnbd_dev_class = class_create("rnbd-client"); err = class_register(&rnbd_dev_class);
if (IS_ERR(rnbd_dev_class)) if (err)
return PTR_ERR(rnbd_dev_class); return err;
rnbd_dev = device_create_with_groups(rnbd_dev_class, NULL, rnbd_dev = device_create_with_groups(&rnbd_dev_class, NULL,
MKDEV(0, 0), NULL, MKDEV(0, 0), NULL,
default_attr_groups, "ctl"); default_attr_groups, "ctl");
if (IS_ERR(rnbd_dev)) { if (IS_ERR(rnbd_dev)) {
@ -666,9 +668,9 @@ int rnbd_clt_create_sysfs_files(void)
return 0; return 0;
dev_destroy: dev_destroy:
device_destroy(rnbd_dev_class, MKDEV(0, 0)); device_destroy(&rnbd_dev_class, MKDEV(0, 0));
cls_destroy: cls_destroy:
class_destroy(rnbd_dev_class); class_unregister(&rnbd_dev_class);
return err; return err;
} }
@ -678,6 +680,6 @@ void rnbd_clt_destroy_sysfs_files(void)
sysfs_remove_group(&rnbd_dev->kobj, &default_attr_group); sysfs_remove_group(&rnbd_dev->kobj, &default_attr_group);
kobject_del(rnbd_devs_kobj); kobject_del(rnbd_devs_kobj);
kobject_put(rnbd_devs_kobj); kobject_put(rnbd_devs_kobj);
device_destroy(rnbd_dev_class, MKDEV(0, 0)); device_destroy(&rnbd_dev_class, MKDEV(0, 0));
class_destroy(rnbd_dev_class); class_unregister(&rnbd_dev_class);
} }

View file

@ -921,11 +921,11 @@ rnbd_clt_session *find_or_create_sess(const char *sessname, bool *first)
return sess; return sess;
} }
static int rnbd_client_open(struct block_device *block_device, fmode_t mode) static int rnbd_client_open(struct gendisk *disk, blk_mode_t mode)
{ {
struct rnbd_clt_dev *dev = block_device->bd_disk->private_data; struct rnbd_clt_dev *dev = disk->private_data;
if (get_disk_ro(dev->gd) && (mode & FMODE_WRITE)) if (get_disk_ro(dev->gd) && (mode & BLK_OPEN_WRITE))
return -EPERM; return -EPERM;
if (dev->dev_state == DEV_STATE_UNMAPPED || if (dev->dev_state == DEV_STATE_UNMAPPED ||
@ -935,7 +935,7 @@ static int rnbd_client_open(struct block_device *block_device, fmode_t mode)
return 0; return 0;
} }
static void rnbd_client_release(struct gendisk *gen, fmode_t mode) static void rnbd_client_release(struct gendisk *gen)
{ {
struct rnbd_clt_dev *dev = gen->private_data; struct rnbd_clt_dev *dev = gen->private_data;

View file

@ -1,23 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* RDMA Network Block Driver
*
* Copyright (c) 2014 - 2018 ProfitBricks GmbH. All rights reserved.
* Copyright (c) 2018 - 2019 1&1 IONOS Cloud GmbH. All rights reserved.
* Copyright (c) 2019 - 2020 1&1 IONOS SE. All rights reserved.
*/
#include "rnbd-proto.h"
const char *rnbd_access_mode_str(enum rnbd_access_mode mode)
{
switch (mode) {
case RNBD_ACCESS_RO:
return "ro";
case RNBD_ACCESS_RW:
return "rw";
case RNBD_ACCESS_MIGRATION:
return "migration";
default:
return "unknown";
}
}

View file

@ -61,6 +61,15 @@ enum rnbd_access_mode {
RNBD_ACCESS_MIGRATION, RNBD_ACCESS_MIGRATION,
}; };
static const __maybe_unused struct {
enum rnbd_access_mode mode;
const char *str;
} rnbd_access_modes[] = {
[RNBD_ACCESS_RO] = {RNBD_ACCESS_RO, "ro"},
[RNBD_ACCESS_RW] = {RNBD_ACCESS_RW, "rw"},
[RNBD_ACCESS_MIGRATION] = {RNBD_ACCESS_MIGRATION, "migration"},
};
/** /**
* struct rnbd_msg_sess_info - initial session info from client to server * struct rnbd_msg_sess_info - initial session info from client to server
* @hdr: message header * @hdr: message header
@ -185,7 +194,6 @@ struct rnbd_msg_io {
enum rnbd_io_flags { enum rnbd_io_flags {
/* Operations */ /* Operations */
RNBD_OP_READ = 0, RNBD_OP_READ = 0,
RNBD_OP_WRITE = 1, RNBD_OP_WRITE = 1,
RNBD_OP_FLUSH = 2, RNBD_OP_FLUSH = 2,
@ -193,15 +201,9 @@ enum rnbd_io_flags {
RNBD_OP_SECURE_ERASE = 4, RNBD_OP_SECURE_ERASE = 4,
RNBD_OP_WRITE_SAME = 5, RNBD_OP_WRITE_SAME = 5,
RNBD_OP_LAST,
/* Flags */ /* Flags */
RNBD_F_SYNC = 1<<(RNBD_OP_BITS + 0), RNBD_F_SYNC = 1<<(RNBD_OP_BITS + 0),
RNBD_F_FUA = 1<<(RNBD_OP_BITS + 1), RNBD_F_FUA = 1<<(RNBD_OP_BITS + 1),
RNBD_F_ALL = (RNBD_F_SYNC | RNBD_F_FUA)
}; };
static inline u32 rnbd_op(u32 flags) static inline u32 rnbd_op(u32 flags)
@ -214,21 +216,6 @@ static inline u32 rnbd_flags(u32 flags)
return flags & ~RNBD_OP_MASK; return flags & ~RNBD_OP_MASK;
} }
static inline bool rnbd_flags_supported(u32 flags)
{
u32 op;
op = rnbd_op(flags);
flags = rnbd_flags(flags);
if (op >= RNBD_OP_LAST)
return false;
if (flags & ~RNBD_F_ALL)
return false;
return true;
}
static inline blk_opf_t rnbd_to_bio_flags(u32 rnbd_opf) static inline blk_opf_t rnbd_to_bio_flags(u32 rnbd_opf)
{ {
blk_opf_t bio_opf; blk_opf_t bio_opf;

View file

@ -9,7 +9,6 @@
#undef pr_fmt #undef pr_fmt
#define pr_fmt(fmt) KBUILD_MODNAME " L" __stringify(__LINE__) ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME " L" __stringify(__LINE__) ": " fmt
#include <uapi/linux/limits.h>
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/sysfs.h> #include <linux/sysfs.h>
#include <linux/stat.h> #include <linux/stat.h>
@ -20,7 +19,9 @@
#include "rnbd-srv.h" #include "rnbd-srv.h"
static struct device *rnbd_dev; static struct device *rnbd_dev;
static struct class *rnbd_dev_class; static const struct class rnbd_dev_class = {
.name = "rnbd-server",
};
static struct kobject *rnbd_devs_kobj; static struct kobject *rnbd_devs_kobj;
static void rnbd_srv_dev_release(struct kobject *kobj) static void rnbd_srv_dev_release(struct kobject *kobj)
@ -88,8 +89,7 @@ static ssize_t read_only_show(struct kobject *kobj, struct kobj_attribute *attr,
sess_dev = container_of(kobj, struct rnbd_srv_sess_dev, kobj); sess_dev = container_of(kobj, struct rnbd_srv_sess_dev, kobj);
return sysfs_emit(page, "%d\n", return sysfs_emit(page, "%d\n", sess_dev->readonly);
!(sess_dev->open_flags & FMODE_WRITE));
} }
static struct kobj_attribute rnbd_srv_dev_session_ro_attr = static struct kobj_attribute rnbd_srv_dev_session_ro_attr =
@ -104,7 +104,7 @@ static ssize_t access_mode_show(struct kobject *kobj,
sess_dev = container_of(kobj, struct rnbd_srv_sess_dev, kobj); sess_dev = container_of(kobj, struct rnbd_srv_sess_dev, kobj);
return sysfs_emit(page, "%s\n", return sysfs_emit(page, "%s\n",
rnbd_access_mode_str(sess_dev->access_mode)); rnbd_access_modes[sess_dev->access_mode].str);
} }
static struct kobj_attribute rnbd_srv_dev_session_access_mode_attr = static struct kobj_attribute rnbd_srv_dev_session_access_mode_attr =
@ -215,12 +215,12 @@ int rnbd_srv_create_sysfs_files(void)
{ {
int err; int err;
rnbd_dev_class = class_create("rnbd-server"); err = class_register(&rnbd_dev_class);
if (IS_ERR(rnbd_dev_class)) if (err)
return PTR_ERR(rnbd_dev_class); return err;
rnbd_dev = device_create(rnbd_dev_class, NULL, rnbd_dev = device_create(&rnbd_dev_class, NULL,
MKDEV(0, 0), NULL, "ctl"); MKDEV(0, 0), NULL, "ctl");
if (IS_ERR(rnbd_dev)) { if (IS_ERR(rnbd_dev)) {
err = PTR_ERR(rnbd_dev); err = PTR_ERR(rnbd_dev);
goto cls_destroy; goto cls_destroy;
@ -234,9 +234,9 @@ int rnbd_srv_create_sysfs_files(void)
return 0; return 0;
dev_destroy: dev_destroy:
device_destroy(rnbd_dev_class, MKDEV(0, 0)); device_destroy(&rnbd_dev_class, MKDEV(0, 0));
cls_destroy: cls_destroy:
class_destroy(rnbd_dev_class); class_unregister(&rnbd_dev_class);
return err; return err;
} }
@ -245,6 +245,6 @@ void rnbd_srv_destroy_sysfs_files(void)
{ {
kobject_del(rnbd_devs_kobj); kobject_del(rnbd_devs_kobj);
kobject_put(rnbd_devs_kobj); kobject_put(rnbd_devs_kobj);
device_destroy(rnbd_dev_class, MKDEV(0, 0)); device_destroy(&rnbd_dev_class, MKDEV(0, 0));
class_destroy(rnbd_dev_class); class_unregister(&rnbd_dev_class);
} }

View file

@ -96,7 +96,7 @@ rnbd_get_sess_dev(int dev_id, struct rnbd_srv_session *srv_sess)
ret = kref_get_unless_zero(&sess_dev->kref); ret = kref_get_unless_zero(&sess_dev->kref);
rcu_read_unlock(); rcu_read_unlock();
if (!sess_dev || !ret) if (!ret)
return ERR_PTR(-ENXIO); return ERR_PTR(-ENXIO);
return sess_dev; return sess_dev;
@ -180,7 +180,7 @@ static void destroy_device(struct kref *kref)
WARN_ONCE(!list_empty(&dev->sess_dev_list), WARN_ONCE(!list_empty(&dev->sess_dev_list),
"Device %s is being destroyed but still in use!\n", "Device %s is being destroyed but still in use!\n",
dev->id); dev->name);
spin_lock(&dev_lock); spin_lock(&dev_lock);
list_del(&dev->list); list_del(&dev->list);
@ -219,10 +219,10 @@ void rnbd_destroy_sess_dev(struct rnbd_srv_sess_dev *sess_dev, bool keep_id)
rnbd_put_sess_dev(sess_dev); rnbd_put_sess_dev(sess_dev);
wait_for_completion(&dc); /* wait for inflights to drop to zero */ wait_for_completion(&dc); /* wait for inflights to drop to zero */
blkdev_put(sess_dev->bdev, sess_dev->open_flags); blkdev_put(sess_dev->bdev, NULL);
mutex_lock(&sess_dev->dev->lock); mutex_lock(&sess_dev->dev->lock);
list_del(&sess_dev->dev_list); list_del(&sess_dev->dev_list);
if (sess_dev->open_flags & FMODE_WRITE) if (!sess_dev->readonly)
sess_dev->dev->open_write_cnt--; sess_dev->dev->open_write_cnt--;
mutex_unlock(&sess_dev->dev->lock); mutex_unlock(&sess_dev->dev->lock);
@ -356,7 +356,7 @@ static int process_msg_open(struct rnbd_srv_session *srv_sess,
const void *msg, size_t len, const void *msg, size_t len,
void *data, size_t datalen); void *data, size_t datalen);
static int process_msg_sess_info(struct rnbd_srv_session *srv_sess, static void process_msg_sess_info(struct rnbd_srv_session *srv_sess,
const void *msg, size_t len, const void *msg, size_t len,
void *data, size_t datalen); void *data, size_t datalen);
@ -384,8 +384,7 @@ static int rnbd_srv_rdma_ev(void *priv, struct rtrs_srv_op *id,
ret = process_msg_open(srv_sess, usr, usrlen, data, datalen); ret = process_msg_open(srv_sess, usr, usrlen, data, datalen);
break; break;
case RNBD_MSG_SESS_INFO: case RNBD_MSG_SESS_INFO:
ret = process_msg_sess_info(srv_sess, usr, usrlen, data, process_msg_sess_info(srv_sess, usr, usrlen, data, datalen);
datalen);
break; break;
default: default:
pr_warn("Received unexpected message type %d from session %s\n", pr_warn("Received unexpected message type %d from session %s\n",
@ -431,7 +430,7 @@ static struct rnbd_srv_dev *rnbd_srv_init_srv_dev(struct block_device *bdev)
if (!dev) if (!dev)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
snprintf(dev->id, sizeof(dev->id), "%pg", bdev); snprintf(dev->name, sizeof(dev->name), "%pg", bdev);
kref_init(&dev->kref); kref_init(&dev->kref);
INIT_LIST_HEAD(&dev->sess_dev_list); INIT_LIST_HEAD(&dev->sess_dev_list);
mutex_init(&dev->lock); mutex_init(&dev->lock);
@ -446,7 +445,7 @@ rnbd_srv_find_or_add_srv_dev(struct rnbd_srv_dev *new_dev)
spin_lock(&dev_lock); spin_lock(&dev_lock);
list_for_each_entry(dev, &dev_list, list) { list_for_each_entry(dev, &dev_list, list) {
if (!strncmp(dev->id, new_dev->id, sizeof(dev->id))) { if (!strncmp(dev->name, new_dev->name, sizeof(dev->name))) {
if (!kref_get_unless_zero(&dev->kref)) if (!kref_get_unless_zero(&dev->kref))
/* /*
* We lost the race, device is almost dead. * We lost the race, device is almost dead.
@ -467,39 +466,38 @@ static int rnbd_srv_check_update_open_perm(struct rnbd_srv_dev *srv_dev,
struct rnbd_srv_session *srv_sess, struct rnbd_srv_session *srv_sess,
enum rnbd_access_mode access_mode) enum rnbd_access_mode access_mode)
{ {
int ret = -EPERM; int ret = 0;
mutex_lock(&srv_dev->lock); mutex_lock(&srv_dev->lock);
switch (access_mode) { switch (access_mode) {
case RNBD_ACCESS_RO: case RNBD_ACCESS_RO:
ret = 0;
break; break;
case RNBD_ACCESS_RW: case RNBD_ACCESS_RW:
if (srv_dev->open_write_cnt == 0) { if (srv_dev->open_write_cnt == 0) {
srv_dev->open_write_cnt++; srv_dev->open_write_cnt++;
ret = 0;
} else { } else {
pr_err("Mapping device '%s' for session %s with RW permissions failed. Device already opened as 'RW' by %d client(s), access mode %s.\n", pr_err("Mapping device '%s' for session %s with RW permissions failed. Device already opened as 'RW' by %d client(s), access mode %s.\n",
srv_dev->id, srv_sess->sessname, srv_dev->name, srv_sess->sessname,
srv_dev->open_write_cnt, srv_dev->open_write_cnt,
rnbd_access_mode_str(access_mode)); rnbd_access_modes[access_mode].str);
ret = -EPERM;
} }
break; break;
case RNBD_ACCESS_MIGRATION: case RNBD_ACCESS_MIGRATION:
if (srv_dev->open_write_cnt < 2) { if (srv_dev->open_write_cnt < 2) {
srv_dev->open_write_cnt++; srv_dev->open_write_cnt++;
ret = 0;
} else { } else {
pr_err("Mapping device '%s' for session %s with migration permissions failed. Device already opened as 'RW' by %d client(s), access mode %s.\n", pr_err("Mapping device '%s' for session %s with migration permissions failed. Device already opened as 'RW' by %d client(s), access mode %s.\n",
srv_dev->id, srv_sess->sessname, srv_dev->name, srv_sess->sessname,
srv_dev->open_write_cnt, srv_dev->open_write_cnt,
rnbd_access_mode_str(access_mode)); rnbd_access_modes[access_mode].str);
ret = -EPERM;
} }
break; break;
default: default:
pr_err("Received mapping request for device '%s' on session %s with invalid access mode: %d\n", pr_err("Received mapping request for device '%s' on session %s with invalid access mode: %d\n",
srv_dev->id, srv_sess->sessname, access_mode); srv_dev->name, srv_sess->sessname, access_mode);
ret = -EINVAL; ret = -EINVAL;
} }
@ -561,7 +559,7 @@ static void rnbd_srv_fill_msg_open_rsp(struct rnbd_msg_open_rsp *rsp,
static struct rnbd_srv_sess_dev * static struct rnbd_srv_sess_dev *
rnbd_srv_create_set_sess_dev(struct rnbd_srv_session *srv_sess, rnbd_srv_create_set_sess_dev(struct rnbd_srv_session *srv_sess,
const struct rnbd_msg_open *open_msg, const struct rnbd_msg_open *open_msg,
struct block_device *bdev, fmode_t open_flags, struct block_device *bdev, bool readonly,
struct rnbd_srv_dev *srv_dev) struct rnbd_srv_dev *srv_dev)
{ {
struct rnbd_srv_sess_dev *sdev = rnbd_sess_dev_alloc(srv_sess); struct rnbd_srv_sess_dev *sdev = rnbd_sess_dev_alloc(srv_sess);
@ -576,7 +574,7 @@ rnbd_srv_create_set_sess_dev(struct rnbd_srv_session *srv_sess,
sdev->bdev = bdev; sdev->bdev = bdev;
sdev->sess = srv_sess; sdev->sess = srv_sess;
sdev->dev = srv_dev; sdev->dev = srv_dev;
sdev->open_flags = open_flags; sdev->readonly = readonly;
sdev->access_mode = open_msg->access_mode; sdev->access_mode = open_msg->access_mode;
return sdev; return sdev;
@ -631,7 +629,7 @@ static char *rnbd_srv_get_full_path(struct rnbd_srv_session *srv_sess,
return full_path; return full_path;
} }
static int process_msg_sess_info(struct rnbd_srv_session *srv_sess, static void process_msg_sess_info(struct rnbd_srv_session *srv_sess,
const void *msg, size_t len, const void *msg, size_t len,
void *data, size_t datalen) void *data, size_t datalen)
{ {
@ -644,8 +642,6 @@ static int process_msg_sess_info(struct rnbd_srv_session *srv_sess,
rsp->hdr.type = cpu_to_le16(RNBD_MSG_SESS_INFO_RSP); rsp->hdr.type = cpu_to_le16(RNBD_MSG_SESS_INFO_RSP);
rsp->ver = srv_sess->ver; rsp->ver = srv_sess->ver;
return 0;
} }
/** /**
@ -681,15 +677,14 @@ static int process_msg_open(struct rnbd_srv_session *srv_sess,
struct rnbd_srv_sess_dev *srv_sess_dev; struct rnbd_srv_sess_dev *srv_sess_dev;
const struct rnbd_msg_open *open_msg = msg; const struct rnbd_msg_open *open_msg = msg;
struct block_device *bdev; struct block_device *bdev;
fmode_t open_flags; blk_mode_t open_flags = BLK_OPEN_READ;
char *full_path; char *full_path;
struct rnbd_msg_open_rsp *rsp = data; struct rnbd_msg_open_rsp *rsp = data;
trace_process_msg_open(srv_sess, open_msg); trace_process_msg_open(srv_sess, open_msg);
open_flags = FMODE_READ;
if (open_msg->access_mode != RNBD_ACCESS_RO) if (open_msg->access_mode != RNBD_ACCESS_RO)
open_flags |= FMODE_WRITE; open_flags |= BLK_OPEN_WRITE;
mutex_lock(&srv_sess->lock); mutex_lock(&srv_sess->lock);
@ -719,7 +714,7 @@ static int process_msg_open(struct rnbd_srv_session *srv_sess,
goto reject; goto reject;
} }
bdev = blkdev_get_by_path(full_path, open_flags, THIS_MODULE); bdev = blkdev_get_by_path(full_path, open_flags, NULL, NULL);
if (IS_ERR(bdev)) { if (IS_ERR(bdev)) {
ret = PTR_ERR(bdev); ret = PTR_ERR(bdev);
pr_err("Opening device '%s' on session %s failed, failed to open the block device, err: %d\n", pr_err("Opening device '%s' on session %s failed, failed to open the block device, err: %d\n",
@ -736,9 +731,9 @@ static int process_msg_open(struct rnbd_srv_session *srv_sess,
goto blkdev_put; goto blkdev_put;
} }
srv_sess_dev = rnbd_srv_create_set_sess_dev(srv_sess, open_msg, srv_sess_dev = rnbd_srv_create_set_sess_dev(srv_sess, open_msg, bdev,
bdev, open_flags, open_msg->access_mode == RNBD_ACCESS_RO,
srv_dev); srv_dev);
if (IS_ERR(srv_sess_dev)) { if (IS_ERR(srv_sess_dev)) {
pr_err("Opening device '%s' on session %s failed, creating sess_dev failed, err: %ld\n", pr_err("Opening device '%s' on session %s failed, creating sess_dev failed, err: %ld\n",
full_path, srv_sess->sessname, PTR_ERR(srv_sess_dev)); full_path, srv_sess->sessname, PTR_ERR(srv_sess_dev));
@ -774,7 +769,7 @@ static int process_msg_open(struct rnbd_srv_session *srv_sess,
list_add(&srv_sess_dev->dev_list, &srv_dev->sess_dev_list); list_add(&srv_sess_dev->dev_list, &srv_dev->sess_dev_list);
mutex_unlock(&srv_dev->lock); mutex_unlock(&srv_dev->lock);
rnbd_srv_info(srv_sess_dev, "Opened device '%s'\n", srv_dev->id); rnbd_srv_info(srv_sess_dev, "Opened device '%s'\n", srv_dev->name);
kfree(full_path); kfree(full_path);
@ -795,7 +790,7 @@ srv_dev_put:
} }
rnbd_put_srv_dev(srv_dev); rnbd_put_srv_dev(srv_dev);
blkdev_put: blkdev_put:
blkdev_put(bdev, open_flags); blkdev_put(bdev, NULL);
free_path: free_path:
kfree(full_path); kfree(full_path);
reject: reject:
@ -808,7 +803,7 @@ static struct rtrs_srv_ctx *rtrs_ctx;
static struct rtrs_srv_ops rtrs_ops; static struct rtrs_srv_ops rtrs_ops;
static int __init rnbd_srv_init_module(void) static int __init rnbd_srv_init_module(void)
{ {
int err; int err = 0;
BUILD_BUG_ON(sizeof(struct rnbd_msg_hdr) != 4); BUILD_BUG_ON(sizeof(struct rnbd_msg_hdr) != 4);
BUILD_BUG_ON(sizeof(struct rnbd_msg_sess_info) != 36); BUILD_BUG_ON(sizeof(struct rnbd_msg_sess_info) != 36);
@ -822,19 +817,17 @@ static int __init rnbd_srv_init_module(void)
}; };
rtrs_ctx = rtrs_srv_open(&rtrs_ops, port_nr); rtrs_ctx = rtrs_srv_open(&rtrs_ops, port_nr);
if (IS_ERR(rtrs_ctx)) { if (IS_ERR(rtrs_ctx)) {
err = PTR_ERR(rtrs_ctx);
pr_err("rtrs_srv_open(), err: %d\n", err); pr_err("rtrs_srv_open(), err: %d\n", err);
return err; return PTR_ERR(rtrs_ctx);
} }
err = rnbd_srv_create_sysfs_files(); err = rnbd_srv_create_sysfs_files();
if (err) { if (err) {
pr_err("rnbd_srv_create_sysfs_files(), err: %d\n", err); pr_err("rnbd_srv_create_sysfs_files(), err: %d\n", err);
rtrs_srv_close(rtrs_ctx); rtrs_srv_close(rtrs_ctx);
return err;
} }
return 0; return err;
} }
static void __exit rnbd_srv_cleanup_module(void) static void __exit rnbd_srv_cleanup_module(void)

View file

@ -35,7 +35,7 @@ struct rnbd_srv_dev {
struct kobject dev_kobj; struct kobject dev_kobj;
struct kobject *dev_sessions_kobj; struct kobject *dev_sessions_kobj;
struct kref kref; struct kref kref;
char id[NAME_MAX]; char name[NAME_MAX];
/* List of rnbd_srv_sess_dev structs */ /* List of rnbd_srv_sess_dev structs */
struct list_head sess_dev_list; struct list_head sess_dev_list;
struct mutex lock; struct mutex lock;
@ -52,7 +52,7 @@ struct rnbd_srv_sess_dev {
struct kobject kobj; struct kobject kobj;
u32 device_id; u32 device_id;
bool keep_id; bool keep_id;
fmode_t open_flags; bool readonly;
struct kref kref; struct kref kref;
struct completion *destroy_comp; struct completion *destroy_comp;
char pathname[NAME_MAX]; char pathname[NAME_MAX];

View file

@ -139,7 +139,7 @@ static int vdc_getgeo(struct block_device *bdev, struct hd_geometry *geo)
* when vdisk_mtype is VD_MEDIA_TYPE_CD or VD_MEDIA_TYPE_DVD. * when vdisk_mtype is VD_MEDIA_TYPE_CD or VD_MEDIA_TYPE_DVD.
* Needed to be able to install inside an ldom from an iso image. * Needed to be able to install inside an ldom from an iso image.
*/ */
static int vdc_ioctl(struct block_device *bdev, fmode_t mode, static int vdc_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned command, unsigned long argument) unsigned command, unsigned long argument)
{ {
struct vdc_port *port = bdev->bd_disk->private_data; struct vdc_port *port = bdev->bd_disk->private_data;

View file

@ -608,20 +608,18 @@ static void setup_medium(struct floppy_state *fs)
} }
} }
static int floppy_open(struct block_device *bdev, fmode_t mode) static int floppy_open(struct gendisk *disk, blk_mode_t mode)
{ {
struct floppy_state *fs = bdev->bd_disk->private_data; struct floppy_state *fs = disk->private_data;
struct swim __iomem *base = fs->swd->base; struct swim __iomem *base = fs->swd->base;
int err; int err;
if (fs->ref_count == -1 || (fs->ref_count && mode & FMODE_EXCL)) if (fs->ref_count == -1 || (fs->ref_count && mode & BLK_OPEN_EXCL))
return -EBUSY; return -EBUSY;
if (mode & BLK_OPEN_EXCL)
if (mode & FMODE_EXCL)
fs->ref_count = -1; fs->ref_count = -1;
else else
fs->ref_count++; fs->ref_count++;
swim_write(base, setup, S_IBM_DRIVE | S_FCLK_DIV2); swim_write(base, setup, S_IBM_DRIVE | S_FCLK_DIV2);
udelay(10); udelay(10);
swim_drive(base, fs->location); swim_drive(base, fs->location);
@ -636,13 +634,13 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
set_capacity(fs->disk, fs->total_secs); set_capacity(fs->disk, fs->total_secs);
if (mode & FMODE_NDELAY) if (mode & BLK_OPEN_NDELAY)
return 0; return 0;
if (mode & (FMODE_READ|FMODE_WRITE)) { if (mode & (BLK_OPEN_READ | BLK_OPEN_WRITE)) {
if (bdev_check_media_change(bdev) && fs->disk_in) if (disk_check_media_change(disk) && fs->disk_in)
fs->ejected = 0; fs->ejected = 0;
if ((mode & FMODE_WRITE) && fs->write_protected) { if ((mode & BLK_OPEN_WRITE) && fs->write_protected) {
err = -EROFS; err = -EROFS;
goto out; goto out;
} }
@ -659,18 +657,18 @@ out:
return err; return err;
} }
static int floppy_unlocked_open(struct block_device *bdev, fmode_t mode) static int floppy_unlocked_open(struct gendisk *disk, blk_mode_t mode)
{ {
int ret; int ret;
mutex_lock(&swim_mutex); mutex_lock(&swim_mutex);
ret = floppy_open(bdev, mode); ret = floppy_open(disk, mode);
mutex_unlock(&swim_mutex); mutex_unlock(&swim_mutex);
return ret; return ret;
} }
static void floppy_release(struct gendisk *disk, fmode_t mode) static void floppy_release(struct gendisk *disk)
{ {
struct floppy_state *fs = disk->private_data; struct floppy_state *fs = disk->private_data;
struct swim __iomem *base = fs->swd->base; struct swim __iomem *base = fs->swd->base;
@ -686,7 +684,7 @@ static void floppy_release(struct gendisk *disk, fmode_t mode)
mutex_unlock(&swim_mutex); mutex_unlock(&swim_mutex);
} }
static int floppy_ioctl(struct block_device *bdev, fmode_t mode, static int floppy_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long param) unsigned int cmd, unsigned long param)
{ {
struct floppy_state *fs = bdev->bd_disk->private_data; struct floppy_state *fs = bdev->bd_disk->private_data;

View file

@ -246,10 +246,9 @@ static int grab_drive(struct floppy_state *fs, enum swim_state state,
int interruptible); int interruptible);
static void release_drive(struct floppy_state *fs); static void release_drive(struct floppy_state *fs);
static int fd_eject(struct floppy_state *fs); static int fd_eject(struct floppy_state *fs);
static int floppy_ioctl(struct block_device *bdev, fmode_t mode, static int floppy_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long param); unsigned int cmd, unsigned long param);
static int floppy_open(struct block_device *bdev, fmode_t mode); static int floppy_open(struct gendisk *disk, blk_mode_t mode);
static void floppy_release(struct gendisk *disk, fmode_t mode);
static unsigned int floppy_check_events(struct gendisk *disk, static unsigned int floppy_check_events(struct gendisk *disk,
unsigned int clearing); unsigned int clearing);
static int floppy_revalidate(struct gendisk *disk); static int floppy_revalidate(struct gendisk *disk);
@ -883,7 +882,7 @@ static int fd_eject(struct floppy_state *fs)
static struct floppy_struct floppy_type = static struct floppy_struct floppy_type =
{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */ { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }; /* 7 1.44MB 3.5" */
static int floppy_locked_ioctl(struct block_device *bdev, fmode_t mode, static int floppy_locked_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long param) unsigned int cmd, unsigned long param)
{ {
struct floppy_state *fs = bdev->bd_disk->private_data; struct floppy_state *fs = bdev->bd_disk->private_data;
@ -911,7 +910,7 @@ static int floppy_locked_ioctl(struct block_device *bdev, fmode_t mode,
return -ENOTTY; return -ENOTTY;
} }
static int floppy_ioctl(struct block_device *bdev, fmode_t mode, static int floppy_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long param) unsigned int cmd, unsigned long param)
{ {
int ret; int ret;
@ -923,9 +922,9 @@ static int floppy_ioctl(struct block_device *bdev, fmode_t mode,
return ret; return ret;
} }
static int floppy_open(struct block_device *bdev, fmode_t mode) static int floppy_open(struct gendisk *disk, blk_mode_t mode)
{ {
struct floppy_state *fs = bdev->bd_disk->private_data; struct floppy_state *fs = disk->private_data;
struct swim3 __iomem *sw = fs->swim3; struct swim3 __iomem *sw = fs->swim3;
int n, err = 0; int n, err = 0;
@ -958,18 +957,18 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
swim3_action(fs, SETMFM); swim3_action(fs, SETMFM);
swim3_select(fs, RELAX); swim3_select(fs, RELAX);
} else if (fs->ref_count == -1 || mode & FMODE_EXCL) } else if (fs->ref_count == -1 || mode & BLK_OPEN_EXCL)
return -EBUSY; return -EBUSY;
if (err == 0 && (mode & FMODE_NDELAY) == 0 if (err == 0 && !(mode & BLK_OPEN_NDELAY) &&
&& (mode & (FMODE_READ|FMODE_WRITE))) { (mode & (BLK_OPEN_READ | BLK_OPEN_WRITE))) {
if (bdev_check_media_change(bdev)) if (disk_check_media_change(disk))
floppy_revalidate(bdev->bd_disk); floppy_revalidate(disk);
if (fs->ejected) if (fs->ejected)
err = -ENXIO; err = -ENXIO;
} }
if (err == 0 && (mode & FMODE_WRITE)) { if (err == 0 && (mode & BLK_OPEN_WRITE)) {
if (fs->write_prot < 0) if (fs->write_prot < 0)
fs->write_prot = swim3_readbit(fs, WRITE_PROT); fs->write_prot = swim3_readbit(fs, WRITE_PROT);
if (fs->write_prot) if (fs->write_prot)
@ -985,7 +984,7 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
return err; return err;
} }
if (mode & FMODE_EXCL) if (mode & BLK_OPEN_EXCL)
fs->ref_count = -1; fs->ref_count = -1;
else else
++fs->ref_count; ++fs->ref_count;
@ -993,18 +992,18 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
return 0; return 0;
} }
static int floppy_unlocked_open(struct block_device *bdev, fmode_t mode) static int floppy_unlocked_open(struct gendisk *disk, blk_mode_t mode)
{ {
int ret; int ret;
mutex_lock(&swim3_mutex); mutex_lock(&swim3_mutex);
ret = floppy_open(bdev, mode); ret = floppy_open(disk, mode);
mutex_unlock(&swim3_mutex); mutex_unlock(&swim3_mutex);
return ret; return ret;
} }
static void floppy_release(struct gendisk *disk, fmode_t mode) static void floppy_release(struct gendisk *disk)
{ {
struct floppy_state *fs = disk->private_data; struct floppy_state *fs = disk->private_data;
struct swim3 __iomem *sw = fs->swim3; struct swim3 __iomem *sw = fs->swim3;

View file

@ -43,6 +43,7 @@
#include <asm/page.h> #include <asm/page.h>
#include <linux/task_work.h> #include <linux/task_work.h>
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/kref.h>
#include <uapi/linux/ublk_cmd.h> #include <uapi/linux/ublk_cmd.h>
#define UBLK_MINORS (1U << MINORBITS) #define UBLK_MINORS (1U << MINORBITS)
@ -54,7 +55,8 @@
| UBLK_F_USER_RECOVERY \ | UBLK_F_USER_RECOVERY \
| UBLK_F_USER_RECOVERY_REISSUE \ | UBLK_F_USER_RECOVERY_REISSUE \
| UBLK_F_UNPRIVILEGED_DEV \ | UBLK_F_UNPRIVILEGED_DEV \
| UBLK_F_CMD_IOCTL_ENCODE) | UBLK_F_CMD_IOCTL_ENCODE \
| UBLK_F_USER_COPY)
/* All UBLK_PARAM_TYPE_* should be included here */ /* All UBLK_PARAM_TYPE_* should be included here */
#define UBLK_PARAM_TYPE_ALL (UBLK_PARAM_TYPE_BASIC | \ #define UBLK_PARAM_TYPE_ALL (UBLK_PARAM_TYPE_BASIC | \
@ -62,7 +64,8 @@
struct ublk_rq_data { struct ublk_rq_data {
struct llist_node node; struct llist_node node;
struct callback_head work;
struct kref ref;
}; };
struct ublk_uring_cmd_pdu { struct ublk_uring_cmd_pdu {
@ -182,8 +185,13 @@ struct ublk_params_header {
__u32 types; __u32 types;
}; };
static inline void __ublk_complete_rq(struct request *req);
static void ublk_complete_rq(struct kref *ref);
static dev_t ublk_chr_devt; static dev_t ublk_chr_devt;
static struct class *ublk_chr_class; static const struct class ublk_chr_class = {
.name = "ublk-char",
};
static DEFINE_IDR(ublk_index_idr); static DEFINE_IDR(ublk_index_idr);
static DEFINE_SPINLOCK(ublk_idr_lock); static DEFINE_SPINLOCK(ublk_idr_lock);
@ -202,6 +210,23 @@ static unsigned int ublks_added; /* protected by ublk_ctl_mutex */
static struct miscdevice ublk_misc; static struct miscdevice ublk_misc;
static inline unsigned ublk_pos_to_hwq(loff_t pos)
{
return ((pos - UBLKSRV_IO_BUF_OFFSET) >> UBLK_QID_OFF) &
UBLK_QID_BITS_MASK;
}
static inline unsigned ublk_pos_to_buf_off(loff_t pos)
{
return (pos - UBLKSRV_IO_BUF_OFFSET) & UBLK_IO_BUF_BITS_MASK;
}
static inline unsigned ublk_pos_to_tag(loff_t pos)
{
return ((pos - UBLKSRV_IO_BUF_OFFSET) >> UBLK_TAG_OFF) &
UBLK_TAG_BITS_MASK;
}
static void ublk_dev_param_basic_apply(struct ublk_device *ub) static void ublk_dev_param_basic_apply(struct ublk_device *ub)
{ {
struct request_queue *q = ub->ub_disk->queue; struct request_queue *q = ub->ub_disk->queue;
@ -290,12 +315,52 @@ static int ublk_apply_params(struct ublk_device *ub)
return 0; return 0;
} }
static inline bool ublk_can_use_task_work(const struct ublk_queue *ubq) static inline bool ublk_support_user_copy(const struct ublk_queue *ubq)
{ {
if (IS_BUILTIN(CONFIG_BLK_DEV_UBLK) && return ubq->flags & UBLK_F_USER_COPY;
!(ubq->flags & UBLK_F_URING_CMD_COMP_IN_TASK)) }
return true;
return false; static inline bool ublk_need_req_ref(const struct ublk_queue *ubq)
{
/*
* read()/write() is involved in user copy, so request reference
* has to be grabbed
*/
return ublk_support_user_copy(ubq);
}
static inline void ublk_init_req_ref(const struct ublk_queue *ubq,
struct request *req)
{
if (ublk_need_req_ref(ubq)) {
struct ublk_rq_data *data = blk_mq_rq_to_pdu(req);
kref_init(&data->ref);
}
}
static inline bool ublk_get_req_ref(const struct ublk_queue *ubq,
struct request *req)
{
if (ublk_need_req_ref(ubq)) {
struct ublk_rq_data *data = blk_mq_rq_to_pdu(req);
return kref_get_unless_zero(&data->ref);
}
return true;
}
static inline void ublk_put_req_ref(const struct ublk_queue *ubq,
struct request *req)
{
if (ublk_need_req_ref(ubq)) {
struct ublk_rq_data *data = blk_mq_rq_to_pdu(req);
kref_put(&data->ref, ublk_complete_rq);
} else {
__ublk_complete_rq(req);
}
} }
static inline bool ublk_need_get_data(const struct ublk_queue *ubq) static inline bool ublk_need_get_data(const struct ublk_queue *ubq)
@ -384,9 +449,9 @@ static void ublk_store_owner_uid_gid(unsigned int *owner_uid,
*owner_gid = from_kgid(&init_user_ns, gid); *owner_gid = from_kgid(&init_user_ns, gid);
} }
static int ublk_open(struct block_device *bdev, fmode_t mode) static int ublk_open(struct gendisk *disk, blk_mode_t mode)
{ {
struct ublk_device *ub = bdev->bd_disk->private_data; struct ublk_device *ub = disk->private_data;
if (capable(CAP_SYS_ADMIN)) if (capable(CAP_SYS_ADMIN))
return 0; return 0;
@ -421,49 +486,39 @@ static const struct block_device_operations ub_fops = {
#define UBLK_MAX_PIN_PAGES 32 #define UBLK_MAX_PIN_PAGES 32
struct ublk_map_data {
const struct request *rq;
unsigned long ubuf;
unsigned int len;
};
struct ublk_io_iter { struct ublk_io_iter {
struct page *pages[UBLK_MAX_PIN_PAGES]; struct page *pages[UBLK_MAX_PIN_PAGES];
unsigned pg_off; /* offset in the 1st page in pages */
int nr_pages; /* how many page pointers in pages */
struct bio *bio; struct bio *bio;
struct bvec_iter iter; struct bvec_iter iter;
}; };
static inline unsigned ublk_copy_io_pages(struct ublk_io_iter *data, /* return how many pages are copied */
unsigned max_bytes, bool to_vm) static void ublk_copy_io_pages(struct ublk_io_iter *data,
size_t total, size_t pg_off, int dir)
{ {
const unsigned total = min_t(unsigned, max_bytes,
PAGE_SIZE - data->pg_off +
((data->nr_pages - 1) << PAGE_SHIFT));
unsigned done = 0; unsigned done = 0;
unsigned pg_idx = 0; unsigned pg_idx = 0;
while (done < total) { while (done < total) {
struct bio_vec bv = bio_iter_iovec(data->bio, data->iter); struct bio_vec bv = bio_iter_iovec(data->bio, data->iter);
const unsigned int bytes = min3(bv.bv_len, total - done, unsigned int bytes = min3(bv.bv_len, (unsigned)total - done,
(unsigned)(PAGE_SIZE - data->pg_off)); (unsigned)(PAGE_SIZE - pg_off));
void *bv_buf = bvec_kmap_local(&bv); void *bv_buf = bvec_kmap_local(&bv);
void *pg_buf = kmap_local_page(data->pages[pg_idx]); void *pg_buf = kmap_local_page(data->pages[pg_idx]);
if (to_vm) if (dir == ITER_DEST)
memcpy(pg_buf + data->pg_off, bv_buf, bytes); memcpy(pg_buf + pg_off, bv_buf, bytes);
else else
memcpy(bv_buf, pg_buf + data->pg_off, bytes); memcpy(bv_buf, pg_buf + pg_off, bytes);
kunmap_local(pg_buf); kunmap_local(pg_buf);
kunmap_local(bv_buf); kunmap_local(bv_buf);
/* advance page array */ /* advance page array */
data->pg_off += bytes; pg_off += bytes;
if (data->pg_off == PAGE_SIZE) { if (pg_off == PAGE_SIZE) {
pg_idx += 1; pg_idx += 1;
data->pg_off = 0; pg_off = 0;
} }
done += bytes; done += bytes;
@ -477,41 +532,58 @@ static inline unsigned ublk_copy_io_pages(struct ublk_io_iter *data,
data->iter = data->bio->bi_iter; data->iter = data->bio->bi_iter;
} }
} }
return done;
} }
static int ublk_copy_user_pages(struct ublk_map_data *data, bool to_vm) static bool ublk_advance_io_iter(const struct request *req,
struct ublk_io_iter *iter, unsigned int offset)
{ {
const unsigned int gup_flags = to_vm ? FOLL_WRITE : 0; struct bio *bio = req->bio;
const unsigned long start_vm = data->ubuf;
unsigned int done = 0;
struct ublk_io_iter iter = {
.pg_off = start_vm & (PAGE_SIZE - 1),
.bio = data->rq->bio,
.iter = data->rq->bio->bi_iter,
};
const unsigned int nr_pages = round_up(data->len +
(start_vm & (PAGE_SIZE - 1)), PAGE_SIZE) >> PAGE_SHIFT;
while (done < nr_pages) { for_each_bio(bio) {
const unsigned to_pin = min_t(unsigned, UBLK_MAX_PIN_PAGES, if (bio->bi_iter.bi_size > offset) {
nr_pages - done); iter->bio = bio;
unsigned i, len; iter->iter = bio->bi_iter;
bio_advance_iter(iter->bio, &iter->iter, offset);
return true;
}
offset -= bio->bi_iter.bi_size;
}
return false;
}
iter.nr_pages = get_user_pages_fast(start_vm + /*
(done << PAGE_SHIFT), to_pin, gup_flags, * Copy data between request pages and io_iter, and 'offset'
iter.pages); * is the start point of linear offset of request.
if (iter.nr_pages <= 0) */
return done == 0 ? iter.nr_pages : done; static size_t ublk_copy_user_pages(const struct request *req,
len = ublk_copy_io_pages(&iter, data->len, to_vm); unsigned offset, struct iov_iter *uiter, int dir)
for (i = 0; i < iter.nr_pages; i++) { {
if (to_vm) struct ublk_io_iter iter;
size_t done = 0;
if (!ublk_advance_io_iter(req, &iter, offset))
return 0;
while (iov_iter_count(uiter) && iter.bio) {
unsigned nr_pages;
ssize_t len;
size_t off;
int i;
len = iov_iter_get_pages2(uiter, iter.pages,
iov_iter_count(uiter),
UBLK_MAX_PIN_PAGES, &off);
if (len <= 0)
return done;
ublk_copy_io_pages(&iter, len, off, dir);
nr_pages = DIV_ROUND_UP(len + off, PAGE_SIZE);
for (i = 0; i < nr_pages; i++) {
if (dir == ITER_DEST)
set_page_dirty(iter.pages[i]); set_page_dirty(iter.pages[i]);
put_page(iter.pages[i]); put_page(iter.pages[i]);
} }
data->len -= len; done += len;
done += iter.nr_pages;
} }
return done; return done;
@ -532,21 +604,23 @@ static int ublk_map_io(const struct ublk_queue *ubq, const struct request *req,
{ {
const unsigned int rq_bytes = blk_rq_bytes(req); const unsigned int rq_bytes = blk_rq_bytes(req);
if (ublk_support_user_copy(ubq))
return rq_bytes;
/* /*
* no zero copy, we delay copy WRITE request data into ublksrv * no zero copy, we delay copy WRITE request data into ublksrv
* context and the big benefit is that pinning pages in current * context and the big benefit is that pinning pages in current
* context is pretty fast, see ublk_pin_user_pages * context is pretty fast, see ublk_pin_user_pages
*/ */
if (ublk_need_map_req(req)) { if (ublk_need_map_req(req)) {
struct ublk_map_data data = { struct iov_iter iter;
.rq = req, struct iovec iov;
.ubuf = io->addr, const int dir = ITER_DEST;
.len = rq_bytes,
};
ublk_copy_user_pages(&data, true); import_single_range(dir, u64_to_user_ptr(io->addr), rq_bytes,
&iov, &iter);
return rq_bytes - data.len; return ublk_copy_user_pages(req, 0, &iter, dir);
} }
return rq_bytes; return rq_bytes;
} }
@ -557,18 +631,19 @@ static int ublk_unmap_io(const struct ublk_queue *ubq,
{ {
const unsigned int rq_bytes = blk_rq_bytes(req); const unsigned int rq_bytes = blk_rq_bytes(req);
if (ublk_support_user_copy(ubq))
return rq_bytes;
if (ublk_need_unmap_req(req)) { if (ublk_need_unmap_req(req)) {
struct ublk_map_data data = { struct iov_iter iter;
.rq = req, struct iovec iov;
.ubuf = io->addr, const int dir = ITER_SOURCE;
.len = io->res,
};
WARN_ON_ONCE(io->res > rq_bytes); WARN_ON_ONCE(io->res > rq_bytes);
ublk_copy_user_pages(&data, false); import_single_range(dir, u64_to_user_ptr(io->addr), io->res,
&iov, &iter);
return io->res - data.len; return ublk_copy_user_pages(req, 0, &iter, dir);
} }
return rq_bytes; return rq_bytes;
} }
@ -648,13 +723,19 @@ static inline bool ubq_daemon_is_dying(struct ublk_queue *ubq)
} }
/* todo: handle partial completion */ /* todo: handle partial completion */
static void ublk_complete_rq(struct request *req) static inline void __ublk_complete_rq(struct request *req)
{ {
struct ublk_queue *ubq = req->mq_hctx->driver_data; struct ublk_queue *ubq = req->mq_hctx->driver_data;
struct ublk_io *io = &ubq->ios[req->tag]; struct ublk_io *io = &ubq->ios[req->tag];
unsigned int unmapped_bytes; unsigned int unmapped_bytes;
blk_status_t res = BLK_STS_OK; blk_status_t res = BLK_STS_OK;
/* called from ublk_abort_queue() code path */
if (io->flags & UBLK_IO_FLAG_ABORTED) {
res = BLK_STS_IOERR;
goto exit;
}
/* failed read IO if nothing is read */ /* failed read IO if nothing is read */
if (!io->res && req_op(req) == REQ_OP_READ) if (!io->res && req_op(req) == REQ_OP_READ)
io->res = -EIO; io->res = -EIO;
@ -694,6 +775,15 @@ exit:
blk_mq_end_request(req, res); blk_mq_end_request(req, res);
} }
static void ublk_complete_rq(struct kref *ref)
{
struct ublk_rq_data *data = container_of(ref, struct ublk_rq_data,
ref);
struct request *req = blk_mq_rq_from_pdu(data);
__ublk_complete_rq(req);
}
/* /*
* Since __ublk_rq_task_work always fails requests immediately during * Since __ublk_rq_task_work always fails requests immediately during
* exiting, __ublk_fail_req() is only called from abort context during * exiting, __ublk_fail_req() is only called from abort context during
@ -712,7 +802,7 @@ static void __ublk_fail_req(struct ublk_queue *ubq, struct ublk_io *io,
if (ublk_queue_can_use_recovery_reissue(ubq)) if (ublk_queue_can_use_recovery_reissue(ubq))
blk_mq_requeue_request(req, false); blk_mq_requeue_request(req, false);
else else
blk_mq_end_request(req, BLK_STS_IOERR); ublk_put_req_ref(ubq, req);
} }
} }
@ -821,6 +911,7 @@ static inline void __ublk_rq_task_work(struct request *req,
mapped_bytes >> 9; mapped_bytes >> 9;
} }
ublk_init_req_ref(ubq, req);
ubq_complete_io_cmd(io, UBLK_IO_RES_OK, issue_flags); ubq_complete_io_cmd(io, UBLK_IO_RES_OK, issue_flags);
} }
@ -852,17 +943,6 @@ static void ublk_rq_task_work_cb(struct io_uring_cmd *cmd, unsigned issue_flags)
ublk_forward_io_cmds(ubq, issue_flags); ublk_forward_io_cmds(ubq, issue_flags);
} }
static void ublk_rq_task_work_fn(struct callback_head *work)
{
struct ublk_rq_data *data = container_of(work,
struct ublk_rq_data, work);
struct request *req = blk_mq_rq_from_pdu(data);
struct ublk_queue *ubq = req->mq_hctx->driver_data;
unsigned issue_flags = IO_URING_F_UNLOCKED;
ublk_forward_io_cmds(ubq, issue_flags);
}
static void ublk_queue_cmd(struct ublk_queue *ubq, struct request *rq) static void ublk_queue_cmd(struct ublk_queue *ubq, struct request *rq)
{ {
struct ublk_rq_data *data = blk_mq_rq_to_pdu(rq); struct ublk_rq_data *data = blk_mq_rq_to_pdu(rq);
@ -886,10 +966,6 @@ static void ublk_queue_cmd(struct ublk_queue *ubq, struct request *rq)
*/ */
if (unlikely(io->flags & UBLK_IO_FLAG_ABORTED)) { if (unlikely(io->flags & UBLK_IO_FLAG_ABORTED)) {
ublk_abort_io_cmds(ubq); ublk_abort_io_cmds(ubq);
} else if (ublk_can_use_task_work(ubq)) {
if (task_work_add(ubq->ubq_daemon, &data->work,
TWA_SIGNAL_NO_IPI))
ublk_abort_io_cmds(ubq);
} else { } else {
struct io_uring_cmd *cmd = io->cmd; struct io_uring_cmd *cmd = io->cmd;
struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd); struct ublk_uring_cmd_pdu *pdu = ublk_get_uring_cmd_pdu(cmd);
@ -961,19 +1037,9 @@ static int ublk_init_hctx(struct blk_mq_hw_ctx *hctx, void *driver_data,
return 0; return 0;
} }
static int ublk_init_rq(struct blk_mq_tag_set *set, struct request *req,
unsigned int hctx_idx, unsigned int numa_node)
{
struct ublk_rq_data *data = blk_mq_rq_to_pdu(req);
init_task_work(&data->work, ublk_rq_task_work_fn);
return 0;
}
static const struct blk_mq_ops ublk_mq_ops = { static const struct blk_mq_ops ublk_mq_ops = {
.queue_rq = ublk_queue_rq, .queue_rq = ublk_queue_rq,
.init_hctx = ublk_init_hctx, .init_hctx = ublk_init_hctx,
.init_request = ublk_init_rq,
.timeout = ublk_timeout, .timeout = ublk_timeout,
}; };
@ -1050,7 +1116,7 @@ static void ublk_commit_completion(struct ublk_device *ub,
req = blk_mq_tag_to_rq(ub->tag_set.tags[qid], tag); req = blk_mq_tag_to_rq(ub->tag_set.tags[qid], tag);
if (req && likely(!blk_should_fake_timeout(req->q))) if (req && likely(!blk_should_fake_timeout(req->q)))
ublk_complete_rq(req); ublk_put_req_ref(ubq, req);
} }
/* /*
@ -1295,6 +1361,14 @@ static inline int ublk_check_cmd_op(u32 cmd_op)
return 0; return 0;
} }
static inline void ublk_fill_io_cmd(struct ublk_io *io,
struct io_uring_cmd *cmd, unsigned long buf_addr)
{
io->cmd = cmd;
io->flags |= UBLK_IO_FLAG_ACTIVE;
io->addr = buf_addr;
}
static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd, static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
unsigned int issue_flags, unsigned int issue_flags,
const struct ublksrv_io_cmd *ub_cmd) const struct ublksrv_io_cmd *ub_cmd)
@ -1340,6 +1414,11 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
^ (_IOC_NR(cmd_op) == UBLK_IO_NEED_GET_DATA)) ^ (_IOC_NR(cmd_op) == UBLK_IO_NEED_GET_DATA))
goto out; goto out;
if (ublk_support_user_copy(ubq) && ub_cmd->addr) {
ret = -EINVAL;
goto out;
}
ret = ublk_check_cmd_op(cmd_op); ret = ublk_check_cmd_op(cmd_op);
if (ret) if (ret)
goto out; goto out;
@ -1358,36 +1437,41 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
*/ */
if (io->flags & UBLK_IO_FLAG_OWNED_BY_SRV) if (io->flags & UBLK_IO_FLAG_OWNED_BY_SRV)
goto out; goto out;
/* FETCH_RQ has to provide IO buffer if NEED GET DATA is not enabled */
if (!ub_cmd->addr && !ublk_need_get_data(ubq))
goto out;
io->cmd = cmd;
io->flags |= UBLK_IO_FLAG_ACTIVE;
io->addr = ub_cmd->addr;
if (!ublk_support_user_copy(ubq)) {
/*
* FETCH_RQ has to provide IO buffer if NEED GET
* DATA is not enabled
*/
if (!ub_cmd->addr && !ublk_need_get_data(ubq))
goto out;
}
ublk_fill_io_cmd(io, cmd, ub_cmd->addr);
ublk_mark_io_ready(ub, ubq); ublk_mark_io_ready(ub, ubq);
break; break;
case UBLK_IO_COMMIT_AND_FETCH_REQ: case UBLK_IO_COMMIT_AND_FETCH_REQ:
req = blk_mq_tag_to_rq(ub->tag_set.tags[ub_cmd->q_id], tag); req = blk_mq_tag_to_rq(ub->tag_set.tags[ub_cmd->q_id], tag);
/*
* COMMIT_AND_FETCH_REQ has to provide IO buffer if NEED GET DATA is
* not enabled or it is Read IO.
*/
if (!ub_cmd->addr && (!ublk_need_get_data(ubq) || req_op(req) == REQ_OP_READ))
goto out;
if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV)) if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV))
goto out; goto out;
io->addr = ub_cmd->addr;
io->flags |= UBLK_IO_FLAG_ACTIVE; if (!ublk_support_user_copy(ubq)) {
io->cmd = cmd; /*
* COMMIT_AND_FETCH_REQ has to provide IO buffer if
* NEED GET DATA is not enabled or it is Read IO.
*/
if (!ub_cmd->addr && (!ublk_need_get_data(ubq) ||
req_op(req) == REQ_OP_READ))
goto out;
}
ublk_fill_io_cmd(io, cmd, ub_cmd->addr);
ublk_commit_completion(ub, ub_cmd); ublk_commit_completion(ub, ub_cmd);
break; break;
case UBLK_IO_NEED_GET_DATA: case UBLK_IO_NEED_GET_DATA:
if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV)) if (!(io->flags & UBLK_IO_FLAG_OWNED_BY_SRV))
goto out; goto out;
io->addr = ub_cmd->addr; ublk_fill_io_cmd(io, cmd, ub_cmd->addr);
io->cmd = cmd;
io->flags |= UBLK_IO_FLAG_ACTIVE;
ublk_handle_need_get_data(ub, ub_cmd->q_id, ub_cmd->tag); ublk_handle_need_get_data(ub, ub_cmd->q_id, ub_cmd->tag);
break; break;
default: default:
@ -1402,6 +1486,36 @@ static int __ublk_ch_uring_cmd(struct io_uring_cmd *cmd,
return -EIOCBQUEUED; return -EIOCBQUEUED;
} }
static inline struct request *__ublk_check_and_get_req(struct ublk_device *ub,
struct ublk_queue *ubq, int tag, size_t offset)
{
struct request *req;
if (!ublk_need_req_ref(ubq))
return NULL;
req = blk_mq_tag_to_rq(ub->tag_set.tags[ubq->q_id], tag);
if (!req)
return NULL;
if (!ublk_get_req_ref(ubq, req))
return NULL;
if (unlikely(!blk_mq_request_started(req) || req->tag != tag))
goto fail_put;
if (!ublk_rq_has_data(req))
goto fail_put;
if (offset > blk_rq_bytes(req))
goto fail_put;
return req;
fail_put:
ublk_put_req_ref(ubq, req);
return NULL;
}
static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags) static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
{ {
/* /*
@ -1419,11 +1533,112 @@ static int ublk_ch_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
return __ublk_ch_uring_cmd(cmd, issue_flags, &ub_cmd); return __ublk_ch_uring_cmd(cmd, issue_flags, &ub_cmd);
} }
static inline bool ublk_check_ubuf_dir(const struct request *req,
int ubuf_dir)
{
/* copy ubuf to request pages */
if (req_op(req) == REQ_OP_READ && ubuf_dir == ITER_SOURCE)
return true;
/* copy request pages to ubuf */
if (req_op(req) == REQ_OP_WRITE && ubuf_dir == ITER_DEST)
return true;
return false;
}
static struct request *ublk_check_and_get_req(struct kiocb *iocb,
struct iov_iter *iter, size_t *off, int dir)
{
struct ublk_device *ub = iocb->ki_filp->private_data;
struct ublk_queue *ubq;
struct request *req;
size_t buf_off;
u16 tag, q_id;
if (!ub)
return ERR_PTR(-EACCES);
if (!user_backed_iter(iter))
return ERR_PTR(-EACCES);
if (ub->dev_info.state == UBLK_S_DEV_DEAD)
return ERR_PTR(-EACCES);
tag = ublk_pos_to_tag(iocb->ki_pos);
q_id = ublk_pos_to_hwq(iocb->ki_pos);
buf_off = ublk_pos_to_buf_off(iocb->ki_pos);
if (q_id >= ub->dev_info.nr_hw_queues)
return ERR_PTR(-EINVAL);
ubq = ublk_get_queue(ub, q_id);
if (!ubq)
return ERR_PTR(-EINVAL);
if (tag >= ubq->q_depth)
return ERR_PTR(-EINVAL);
req = __ublk_check_and_get_req(ub, ubq, tag, buf_off);
if (!req)
return ERR_PTR(-EINVAL);
if (!req->mq_hctx || !req->mq_hctx->driver_data)
goto fail;
if (!ublk_check_ubuf_dir(req, dir))
goto fail;
*off = buf_off;
return req;
fail:
ublk_put_req_ref(ubq, req);
return ERR_PTR(-EACCES);
}
static ssize_t ublk_ch_read_iter(struct kiocb *iocb, struct iov_iter *to)
{
struct ublk_queue *ubq;
struct request *req;
size_t buf_off;
size_t ret;
req = ublk_check_and_get_req(iocb, to, &buf_off, ITER_DEST);
if (IS_ERR(req))
return PTR_ERR(req);
ret = ublk_copy_user_pages(req, buf_off, to, ITER_DEST);
ubq = req->mq_hctx->driver_data;
ublk_put_req_ref(ubq, req);
return ret;
}
static ssize_t ublk_ch_write_iter(struct kiocb *iocb, struct iov_iter *from)
{
struct ublk_queue *ubq;
struct request *req;
size_t buf_off;
size_t ret;
req = ublk_check_and_get_req(iocb, from, &buf_off, ITER_SOURCE);
if (IS_ERR(req))
return PTR_ERR(req);
ret = ublk_copy_user_pages(req, buf_off, from, ITER_SOURCE);
ubq = req->mq_hctx->driver_data;
ublk_put_req_ref(ubq, req);
return ret;
}
static const struct file_operations ublk_ch_fops = { static const struct file_operations ublk_ch_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = ublk_ch_open, .open = ublk_ch_open,
.release = ublk_ch_release, .release = ublk_ch_release,
.llseek = no_llseek, .llseek = no_llseek,
.read_iter = ublk_ch_read_iter,
.write_iter = ublk_ch_write_iter,
.uring_cmd = ublk_ch_uring_cmd, .uring_cmd = ublk_ch_uring_cmd,
.mmap = ublk_ch_mmap, .mmap = ublk_ch_mmap,
}; };
@ -1547,7 +1762,7 @@ static int ublk_add_chdev(struct ublk_device *ub)
dev->parent = ublk_misc.this_device; dev->parent = ublk_misc.this_device;
dev->devt = MKDEV(MAJOR(ublk_chr_devt), minor); dev->devt = MKDEV(MAJOR(ublk_chr_devt), minor);
dev->class = ublk_chr_class; dev->class = &ublk_chr_class;
dev->release = ublk_cdev_rel; dev->release = ublk_cdev_rel;
device_initialize(dev); device_initialize(dev);
@ -1818,10 +2033,12 @@ static int ublk_ctrl_add_dev(struct io_uring_cmd *cmd)
*/ */
ub->dev_info.flags &= UBLK_F_ALL; ub->dev_info.flags &= UBLK_F_ALL;
if (!IS_BUILTIN(CONFIG_BLK_DEV_UBLK)) ub->dev_info.flags |= UBLK_F_CMD_IOCTL_ENCODE |
ub->dev_info.flags |= UBLK_F_URING_CMD_COMP_IN_TASK; UBLK_F_URING_CMD_COMP_IN_TASK;
ub->dev_info.flags |= UBLK_F_CMD_IOCTL_ENCODE; /* GET_DATA isn't needed any more with USER_COPY */
if (ub->dev_info.flags & UBLK_F_USER_COPY)
ub->dev_info.flags &= ~UBLK_F_NEED_GET_DATA;
/* We are not ready to support zero copy */ /* We are not ready to support zero copy */
ub->dev_info.flags &= ~UBLK_F_SUPPORT_ZERO_COPY; ub->dev_info.flags &= ~UBLK_F_SUPPORT_ZERO_COPY;
@ -2133,6 +2350,21 @@ static int ublk_ctrl_end_recovery(struct ublk_device *ub,
return ret; return ret;
} }
static int ublk_ctrl_get_features(struct io_uring_cmd *cmd)
{
const struct ublksrv_ctrl_cmd *header = io_uring_sqe_cmd(cmd->sqe);
void __user *argp = (void __user *)(unsigned long)header->addr;
u64 features = UBLK_F_ALL & ~UBLK_F_SUPPORT_ZERO_COPY;
if (header->len != UBLK_FEATURES_LEN || !header->addr)
return -EINVAL;
if (copy_to_user(argp, &features, UBLK_FEATURES_LEN))
return -EFAULT;
return 0;
}
/* /*
* All control commands are sent via /dev/ublk-control, so we have to check * All control commands are sent via /dev/ublk-control, so we have to check
* the destination device's permission * the destination device's permission
@ -2213,6 +2445,7 @@ static int ublk_ctrl_uring_cmd_permission(struct ublk_device *ub,
case UBLK_CMD_GET_DEV_INFO2: case UBLK_CMD_GET_DEV_INFO2:
case UBLK_CMD_GET_QUEUE_AFFINITY: case UBLK_CMD_GET_QUEUE_AFFINITY:
case UBLK_CMD_GET_PARAMS: case UBLK_CMD_GET_PARAMS:
case (_IOC_NR(UBLK_U_CMD_GET_FEATURES)):
mask = MAY_READ; mask = MAY_READ;
break; break;
case UBLK_CMD_START_DEV: case UBLK_CMD_START_DEV:
@ -2262,6 +2495,11 @@ static int ublk_ctrl_uring_cmd(struct io_uring_cmd *cmd,
if (ret) if (ret)
goto out; goto out;
if (cmd_op == UBLK_U_CMD_GET_FEATURES) {
ret = ublk_ctrl_get_features(cmd);
goto out;
}
if (_IOC_NR(cmd_op) != UBLK_CMD_ADD_DEV) { if (_IOC_NR(cmd_op) != UBLK_CMD_ADD_DEV) {
ret = -ENODEV; ret = -ENODEV;
ub = ublk_get_device_from_id(header->dev_id); ub = ublk_get_device_from_id(header->dev_id);
@ -2337,6 +2575,9 @@ static int __init ublk_init(void)
{ {
int ret; int ret;
BUILD_BUG_ON((u64)UBLKSRV_IO_BUF_OFFSET +
UBLKSRV_IO_BUF_TOTAL_SIZE < UBLKSRV_IO_BUF_OFFSET);
init_waitqueue_head(&ublk_idr_wq); init_waitqueue_head(&ublk_idr_wq);
ret = misc_register(&ublk_misc); ret = misc_register(&ublk_misc);
@ -2347,11 +2588,10 @@ static int __init ublk_init(void)
if (ret) if (ret)
goto unregister_mis; goto unregister_mis;
ublk_chr_class = class_create("ublk-char"); ret = class_register(&ublk_chr_class);
if (IS_ERR(ublk_chr_class)) { if (ret)
ret = PTR_ERR(ublk_chr_class);
goto free_chrdev_region; goto free_chrdev_region;
}
return 0; return 0;
free_chrdev_region: free_chrdev_region:
@ -2369,7 +2609,7 @@ static void __exit ublk_exit(void)
idr_for_each_entry(&ublk_index_idr, ub, id) idr_for_each_entry(&ublk_index_idr, ub, id)
ublk_remove(ub); ublk_remove(ub);
class_destroy(ublk_chr_class); class_unregister(&ublk_chr_class);
misc_deregister(&ublk_misc); misc_deregister(&ublk_misc);
idr_destroy(&ublk_index_idr); idr_destroy(&ublk_index_idr);

View file

@ -473,7 +473,7 @@ static void xenvbd_sysfs_delif(struct xenbus_device *dev)
static void xen_vbd_free(struct xen_vbd *vbd) static void xen_vbd_free(struct xen_vbd *vbd)
{ {
if (vbd->bdev) if (vbd->bdev)
blkdev_put(vbd->bdev, vbd->readonly ? FMODE_READ : FMODE_WRITE); blkdev_put(vbd->bdev, NULL);
vbd->bdev = NULL; vbd->bdev = NULL;
} }
@ -492,7 +492,7 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle,
vbd->pdevice = MKDEV(major, minor); vbd->pdevice = MKDEV(major, minor);
bdev = blkdev_get_by_dev(vbd->pdevice, vbd->readonly ? bdev = blkdev_get_by_dev(vbd->pdevice, vbd->readonly ?
FMODE_READ : FMODE_WRITE, NULL); BLK_OPEN_READ : BLK_OPEN_WRITE, NULL, NULL);
if (IS_ERR(bdev)) { if (IS_ERR(bdev)) {
pr_warn("xen_vbd_create: device %08x could not be opened\n", pr_warn("xen_vbd_create: device %08x could not be opened\n",

View file

@ -509,7 +509,7 @@ static int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg)
return 0; return 0;
} }
static int blkif_ioctl(struct block_device *bdev, fmode_t mode, static int blkif_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned command, unsigned long argument) unsigned command, unsigned long argument)
{ {
struct blkfront_info *info = bdev->bd_disk->private_data; struct blkfront_info *info = bdev->bd_disk->private_data;

View file

@ -140,16 +140,14 @@ static void get_chipram(void)
return; return;
} }
static int z2_open(struct block_device *bdev, fmode_t mode) static int z2_open(struct gendisk *disk, blk_mode_t mode)
{ {
int device; int device = disk->first_minor;
int max_z2_map = (Z2RAM_SIZE / Z2RAM_CHUNKSIZE) * sizeof(z2ram_map[0]); int max_z2_map = (Z2RAM_SIZE / Z2RAM_CHUNKSIZE) * sizeof(z2ram_map[0]);
int max_chip_map = (amiga_chip_size / Z2RAM_CHUNKSIZE) * int max_chip_map = (amiga_chip_size / Z2RAM_CHUNKSIZE) *
sizeof(z2ram_map[0]); sizeof(z2ram_map[0]);
int rc = -ENOMEM; int rc = -ENOMEM;
device = MINOR(bdev->bd_dev);
mutex_lock(&z2ram_mutex); mutex_lock(&z2ram_mutex);
if (current_device != -1 && current_device != device) { if (current_device != -1 && current_device != device) {
rc = -EBUSY; rc = -EBUSY;
@ -290,7 +288,7 @@ err_out:
return rc; return rc;
} }
static void z2_release(struct gendisk *disk, fmode_t mode) static void z2_release(struct gendisk *disk)
{ {
mutex_lock(&z2ram_mutex); mutex_lock(&z2ram_mutex);
if (current_device == -1) { if (current_device == -1) {

View file

@ -420,7 +420,7 @@ static void reset_bdev(struct zram *zram)
return; return;
bdev = zram->bdev; bdev = zram->bdev;
blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); blkdev_put(bdev, zram);
/* hope filp_close flush all of IO */ /* hope filp_close flush all of IO */
filp_close(zram->backing_dev, NULL); filp_close(zram->backing_dev, NULL);
zram->backing_dev = NULL; zram->backing_dev = NULL;
@ -507,8 +507,8 @@ static ssize_t backing_dev_store(struct device *dev,
goto out; goto out;
} }
bdev = blkdev_get_by_dev(inode->i_rdev, bdev = blkdev_get_by_dev(inode->i_rdev, BLK_OPEN_READ | BLK_OPEN_WRITE,
FMODE_READ | FMODE_WRITE | FMODE_EXCL, zram); zram, NULL);
if (IS_ERR(bdev)) { if (IS_ERR(bdev)) {
err = PTR_ERR(bdev); err = PTR_ERR(bdev);
bdev = NULL; bdev = NULL;
@ -539,7 +539,7 @@ out:
kvfree(bitmap); kvfree(bitmap);
if (bdev) if (bdev)
blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); blkdev_put(bdev, zram);
if (backing_dev) if (backing_dev)
filp_close(backing_dev, NULL); filp_close(backing_dev, NULL);
@ -700,7 +700,7 @@ static ssize_t writeback_store(struct device *dev,
bio_init(&bio, zram->bdev, &bio_vec, 1, bio_init(&bio, zram->bdev, &bio_vec, 1,
REQ_OP_WRITE | REQ_SYNC); REQ_OP_WRITE | REQ_SYNC);
bio.bi_iter.bi_sector = blk_idx * (PAGE_SIZE >> 9); bio.bi_iter.bi_sector = blk_idx * (PAGE_SIZE >> 9);
bio_add_page(&bio, page, PAGE_SIZE, 0); __bio_add_page(&bio, page, PAGE_SIZE, 0);
/* /*
* XXX: A single page IO would be inefficient for write * XXX: A single page IO would be inefficient for write
@ -2097,19 +2097,16 @@ static ssize_t reset_store(struct device *dev,
return len; return len;
} }
static int zram_open(struct block_device *bdev, fmode_t mode) static int zram_open(struct gendisk *disk, blk_mode_t mode)
{ {
int ret = 0; struct zram *zram = disk->private_data;
struct zram *zram;
WARN_ON(!mutex_is_locked(&bdev->bd_disk->open_mutex)); WARN_ON(!mutex_is_locked(&disk->open_mutex));
zram = bdev->bd_disk->private_data;
/* zram was claimed to reset so open request fails */ /* zram was claimed to reset so open request fails */
if (zram->claim) if (zram->claim)
ret = -EBUSY; return -EBUSY;
return 0;
return ret;
} }
static const struct block_device_operations zram_devops = { static const struct block_device_operations zram_devops = {

View file

@ -264,6 +264,7 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/nospec.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/cdrom.h> #include <linux/cdrom.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
@ -978,15 +979,6 @@ static void cdrom_dvd_rw_close_write(struct cdrom_device_info *cdi)
cdi->media_written = 0; cdi->media_written = 0;
} }
static int cdrom_close_write(struct cdrom_device_info *cdi)
{
#if 0
return cdrom_flush_cache(cdi);
#else
return 0;
#endif
}
/* badly broken, I know. Is due for a fixup anytime. */ /* badly broken, I know. Is due for a fixup anytime. */
static void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype *tracks) static void cdrom_count_tracks(struct cdrom_device_info *cdi, tracktype *tracks)
{ {
@ -1155,8 +1147,7 @@ clean_up_and_return:
* is in their own interest: device control becomes a lot easier * is in their own interest: device control becomes a lot easier
* this way. * this way.
*/ */
int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, int cdrom_open(struct cdrom_device_info *cdi, blk_mode_t mode)
fmode_t mode)
{ {
int ret; int ret;
@ -1165,7 +1156,7 @@ int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev,
/* if this was a O_NONBLOCK open and we should honor the flags, /* if this was a O_NONBLOCK open and we should honor the flags,
* do a quick open without drive/disc integrity checks. */ * do a quick open without drive/disc integrity checks. */
cdi->use_count++; cdi->use_count++;
if ((mode & FMODE_NDELAY) && (cdi->options & CDO_USE_FFLAGS)) { if ((mode & BLK_OPEN_NDELAY) && (cdi->options & CDO_USE_FFLAGS)) {
ret = cdi->ops->open(cdi, 1); ret = cdi->ops->open(cdi, 1);
} else { } else {
ret = open_for_data(cdi); ret = open_for_data(cdi);
@ -1173,7 +1164,7 @@ int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev,
goto err; goto err;
if (CDROM_CAN(CDC_GENERIC_PACKET)) if (CDROM_CAN(CDC_GENERIC_PACKET))
cdrom_mmc3_profile(cdi); cdrom_mmc3_profile(cdi);
if (mode & FMODE_WRITE) { if (mode & BLK_OPEN_WRITE) {
ret = -EROFS; ret = -EROFS;
if (cdrom_open_write(cdi)) if (cdrom_open_write(cdi))
goto err_release; goto err_release;
@ -1182,6 +1173,7 @@ int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev,
ret = 0; ret = 0;
cdi->media_written = 0; cdi->media_written = 0;
} }
cdi->opened_for_data = true;
} }
if (ret) if (ret)
@ -1259,10 +1251,9 @@ static int check_for_audio_disc(struct cdrom_device_info *cdi,
return 0; return 0;
} }
void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode) void cdrom_release(struct cdrom_device_info *cdi)
{ {
const struct cdrom_device_ops *cdo = cdi->ops; const struct cdrom_device_ops *cdo = cdi->ops;
int opened_for_data;
cd_dbg(CD_CLOSE, "entering cdrom_release\n"); cd_dbg(CD_CLOSE, "entering cdrom_release\n");
@ -1280,20 +1271,12 @@ void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode)
} }
} }
opened_for_data = !(cdi->options & CDO_USE_FFLAGS) ||
!(mode & FMODE_NDELAY);
/*
* flush cache on last write release
*/
if (CDROM_CAN(CDC_RAM) && !cdi->use_count && cdi->for_data)
cdrom_close_write(cdi);
cdo->release(cdi); cdo->release(cdi);
if (cdi->use_count == 0) { /* last process that closes dev*/
if (opened_for_data && if (cdi->use_count == 0 && cdi->opened_for_data) {
cdi->options & CDO_AUTO_EJECT && CDROM_CAN(CDC_OPEN_TRAY)) if (cdi->options & CDO_AUTO_EJECT && CDROM_CAN(CDC_OPEN_TRAY))
cdo->tray_move(cdi, 1); cdo->tray_move(cdi, 1);
cdi->opened_for_data = false;
} }
} }
EXPORT_SYMBOL(cdrom_release); EXPORT_SYMBOL(cdrom_release);
@ -2329,6 +2312,9 @@ static int cdrom_ioctl_media_changed(struct cdrom_device_info *cdi,
if (arg >= cdi->capacity) if (arg >= cdi->capacity)
return -EINVAL; return -EINVAL;
/* Prevent arg from speculatively bypassing the length check */
barrier_nospec();
info = kmalloc(sizeof(*info), GFP_KERNEL); info = kmalloc(sizeof(*info), GFP_KERNEL);
if (!info) if (!info)
return -ENOMEM; return -ENOMEM;
@ -3337,7 +3323,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
* ATAPI / SCSI specific code now mainly resides in mmc_ioctl(). * ATAPI / SCSI specific code now mainly resides in mmc_ioctl().
*/ */
int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev,
fmode_t mode, unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
int ret; int ret;

View file

@ -474,19 +474,19 @@ static const struct cdrom_device_ops gdrom_ops = {
CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R, CDC_RESET | CDC_DRIVE_STATUS | CDC_CD_R,
}; };
static int gdrom_bdops_open(struct block_device *bdev, fmode_t mode) static int gdrom_bdops_open(struct gendisk *disk, blk_mode_t mode)
{ {
int ret; int ret;
bdev_check_media_change(bdev); disk_check_media_change(disk);
mutex_lock(&gdrom_mutex); mutex_lock(&gdrom_mutex);
ret = cdrom_open(gd.cd_info, bdev, mode); ret = cdrom_open(gd.cd_info);
mutex_unlock(&gdrom_mutex); mutex_unlock(&gdrom_mutex);
return ret; return ret;
} }
static void gdrom_bdops_release(struct gendisk *disk, fmode_t mode) static void gdrom_bdops_release(struct gendisk *disk)
{ {
mutex_lock(&gdrom_mutex); mutex_lock(&gdrom_mutex);
cdrom_release(gd.cd_info, mode); cdrom_release(gd.cd_info, mode);
@ -499,13 +499,13 @@ static unsigned int gdrom_bdops_check_events(struct gendisk *disk,
return cdrom_check_events(gd.cd_info, clearing); return cdrom_check_events(gd.cd_info, clearing);
} }
static int gdrom_bdops_ioctl(struct block_device *bdev, fmode_t mode, static int gdrom_bdops_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned cmd, unsigned long arg) unsigned cmd, unsigned long arg)
{ {
int ret; int ret;
mutex_lock(&gdrom_mutex); mutex_lock(&gdrom_mutex);
ret = cdrom_ioctl(gd.cd_info, bdev, mode, cmd, arg); ret = cdrom_ioctl(gd.cd_info, bdev, cmd, arg);
mutex_unlock(&gdrom_mutex); mutex_unlock(&gdrom_mutex);
return ret; return ret;

View file

@ -275,7 +275,7 @@ struct bcache_device {
int (*cache_miss)(struct btree *b, struct search *s, int (*cache_miss)(struct btree *b, struct search *s,
struct bio *bio, unsigned int sectors); struct bio *bio, unsigned int sectors);
int (*ioctl)(struct bcache_device *d, fmode_t mode, int (*ioctl)(struct bcache_device *d, blk_mode_t mode,
unsigned int cmd, unsigned long arg); unsigned int cmd, unsigned long arg);
}; };
@ -1004,11 +1004,11 @@ extern struct workqueue_struct *bch_flush_wq;
extern struct mutex bch_register_lock; extern struct mutex bch_register_lock;
extern struct list_head bch_cache_sets; extern struct list_head bch_cache_sets;
extern struct kobj_type bch_cached_dev_ktype; extern const struct kobj_type bch_cached_dev_ktype;
extern struct kobj_type bch_flash_dev_ktype; extern const struct kobj_type bch_flash_dev_ktype;
extern struct kobj_type bch_cache_set_ktype; extern const struct kobj_type bch_cache_set_ktype;
extern struct kobj_type bch_cache_set_internal_ktype; extern const struct kobj_type bch_cache_set_internal_ktype;
extern struct kobj_type bch_cache_ktype; extern const struct kobj_type bch_cache_ktype;
void bch_cached_dev_release(struct kobject *kobj); void bch_cached_dev_release(struct kobject *kobj);
void bch_flash_dev_release(struct kobject *kobj); void bch_flash_dev_release(struct kobject *kobj);

View file

@ -885,7 +885,7 @@ static struct btree *mca_cannibalize(struct cache_set *c, struct btree_op *op,
* cannibalize_bucket() will take. This means every time we unlock the root of * cannibalize_bucket() will take. This means every time we unlock the root of
* the btree, we need to release this lock if we have it held. * the btree, we need to release this lock if we have it held.
*/ */
static void bch_cannibalize_unlock(struct cache_set *c) void bch_cannibalize_unlock(struct cache_set *c)
{ {
spin_lock(&c->btree_cannibalize_lock); spin_lock(&c->btree_cannibalize_lock);
if (c->btree_cache_alloc_lock == current) { if (c->btree_cache_alloc_lock == current) {
@ -1090,10 +1090,12 @@ struct btree *__bch_btree_node_alloc(struct cache_set *c, struct btree_op *op,
struct btree *parent) struct btree *parent)
{ {
BKEY_PADDED(key) k; BKEY_PADDED(key) k;
struct btree *b = ERR_PTR(-EAGAIN); struct btree *b;
mutex_lock(&c->bucket_lock); mutex_lock(&c->bucket_lock);
retry: retry:
/* return ERR_PTR(-EAGAIN) when it fails */
b = ERR_PTR(-EAGAIN);
if (__bch_bucket_alloc_set(c, RESERVE_BTREE, &k.key, wait)) if (__bch_bucket_alloc_set(c, RESERVE_BTREE, &k.key, wait))
goto err; goto err;
@ -1138,7 +1140,7 @@ static struct btree *btree_node_alloc_replacement(struct btree *b,
{ {
struct btree *n = bch_btree_node_alloc(b->c, op, b->level, b->parent); struct btree *n = bch_btree_node_alloc(b->c, op, b->level, b->parent);
if (!IS_ERR_OR_NULL(n)) { if (!IS_ERR(n)) {
mutex_lock(&n->write_lock); mutex_lock(&n->write_lock);
bch_btree_sort_into(&b->keys, &n->keys, &b->c->sort); bch_btree_sort_into(&b->keys, &n->keys, &b->c->sort);
bkey_copy_key(&n->key, &b->key); bkey_copy_key(&n->key, &b->key);
@ -1340,7 +1342,7 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
memset(new_nodes, 0, sizeof(new_nodes)); memset(new_nodes, 0, sizeof(new_nodes));
closure_init_stack(&cl); closure_init_stack(&cl);
while (nodes < GC_MERGE_NODES && !IS_ERR_OR_NULL(r[nodes].b)) while (nodes < GC_MERGE_NODES && !IS_ERR(r[nodes].b))
keys += r[nodes++].keys; keys += r[nodes++].keys;
blocks = btree_default_blocks(b->c) * 2 / 3; blocks = btree_default_blocks(b->c) * 2 / 3;
@ -1352,7 +1354,7 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
for (i = 0; i < nodes; i++) { for (i = 0; i < nodes; i++) {
new_nodes[i] = btree_node_alloc_replacement(r[i].b, NULL); new_nodes[i] = btree_node_alloc_replacement(r[i].b, NULL);
if (IS_ERR_OR_NULL(new_nodes[i])) if (IS_ERR(new_nodes[i]))
goto out_nocoalesce; goto out_nocoalesce;
} }
@ -1487,7 +1489,7 @@ out_nocoalesce:
bch_keylist_free(&keylist); bch_keylist_free(&keylist);
for (i = 0; i < nodes; i++) for (i = 0; i < nodes; i++)
if (!IS_ERR_OR_NULL(new_nodes[i])) { if (!IS_ERR(new_nodes[i])) {
btree_node_free(new_nodes[i]); btree_node_free(new_nodes[i]);
rw_unlock(true, new_nodes[i]); rw_unlock(true, new_nodes[i]);
} }
@ -1669,7 +1671,7 @@ static int bch_btree_gc_root(struct btree *b, struct btree_op *op,
if (should_rewrite) { if (should_rewrite) {
n = btree_node_alloc_replacement(b, NULL); n = btree_node_alloc_replacement(b, NULL);
if (!IS_ERR_OR_NULL(n)) { if (!IS_ERR(n)) {
bch_btree_node_write_sync(n); bch_btree_node_write_sync(n);
bch_btree_set_root(n); bch_btree_set_root(n);
@ -1968,6 +1970,15 @@ static int bch_btree_check_thread(void *arg)
c->gc_stats.nodes++; c->gc_stats.nodes++;
bch_btree_op_init(&op, 0); bch_btree_op_init(&op, 0);
ret = bcache_btree(check_recurse, p, c->root, &op); ret = bcache_btree(check_recurse, p, c->root, &op);
/*
* The op may be added to cache_set's btree_cache_wait
* in mca_cannibalize(), must ensure it is removed from
* the list and release btree_cache_alloc_lock before
* free op memory.
* Otherwise, the btree_cache_wait will be damaged.
*/
bch_cannibalize_unlock(c);
finish_wait(&c->btree_cache_wait, &(&op)->wait);
if (ret) if (ret)
goto out; goto out;
} }

View file

@ -282,6 +282,7 @@ void bch_initial_gc_finish(struct cache_set *c);
void bch_moving_gc(struct cache_set *c); void bch_moving_gc(struct cache_set *c);
int bch_btree_check(struct cache_set *c); int bch_btree_check(struct cache_set *c);
void bch_initial_mark_key(struct cache_set *c, int level, struct bkey *k); void bch_initial_mark_key(struct cache_set *c, int level, struct bkey *k);
void bch_cannibalize_unlock(struct cache_set *c);
static inline void wake_up_gc(struct cache_set *c) static inline void wake_up_gc(struct cache_set *c)
{ {

View file

@ -1228,7 +1228,7 @@ void cached_dev_submit_bio(struct bio *bio)
detached_dev_do_request(d, bio, orig_bdev, start_time); detached_dev_do_request(d, bio, orig_bdev, start_time);
} }
static int cached_dev_ioctl(struct bcache_device *d, fmode_t mode, static int cached_dev_ioctl(struct bcache_device *d, blk_mode_t mode,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
struct cached_dev *dc = container_of(d, struct cached_dev, disk); struct cached_dev *dc = container_of(d, struct cached_dev, disk);
@ -1318,7 +1318,7 @@ void flash_dev_submit_bio(struct bio *bio)
continue_at(cl, search_free, NULL); continue_at(cl, search_free, NULL);
} }
static int flash_dev_ioctl(struct bcache_device *d, fmode_t mode, static int flash_dev_ioctl(struct bcache_device *d, blk_mode_t mode,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
return -ENOTTY; return -ENOTTY;

View file

@ -18,7 +18,6 @@ struct cache_stats {
unsigned long cache_misses; unsigned long cache_misses;
unsigned long cache_bypass_hits; unsigned long cache_bypass_hits;
unsigned long cache_bypass_misses; unsigned long cache_bypass_misses;
unsigned long cache_readaheads;
unsigned long cache_miss_collisions; unsigned long cache_miss_collisions;
unsigned long sectors_bypassed; unsigned long sectors_bypassed;

View file

@ -732,9 +732,9 @@ out:
/* Bcache device */ /* Bcache device */
static int open_dev(struct block_device *b, fmode_t mode) static int open_dev(struct gendisk *disk, blk_mode_t mode)
{ {
struct bcache_device *d = b->bd_disk->private_data; struct bcache_device *d = disk->private_data;
if (test_bit(BCACHE_DEV_CLOSING, &d->flags)) if (test_bit(BCACHE_DEV_CLOSING, &d->flags))
return -ENXIO; return -ENXIO;
@ -743,14 +743,14 @@ static int open_dev(struct block_device *b, fmode_t mode)
return 0; return 0;
} }
static void release_dev(struct gendisk *b, fmode_t mode) static void release_dev(struct gendisk *b)
{ {
struct bcache_device *d = b->private_data; struct bcache_device *d = b->private_data;
closure_put(&d->cl); closure_put(&d->cl);
} }
static int ioctl_dev(struct block_device *b, fmode_t mode, static int ioctl_dev(struct block_device *b, blk_mode_t mode,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
struct bcache_device *d = b->bd_disk->private_data; struct bcache_device *d = b->bd_disk->private_data;
@ -1369,7 +1369,7 @@ static void cached_dev_free(struct closure *cl)
put_page(virt_to_page(dc->sb_disk)); put_page(virt_to_page(dc->sb_disk));
if (!IS_ERR_OR_NULL(dc->bdev)) if (!IS_ERR_OR_NULL(dc->bdev))
blkdev_put(dc->bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); blkdev_put(dc->bdev, bcache_kobj);
wake_up(&unregister_wait); wake_up(&unregister_wait);
@ -1723,7 +1723,7 @@ static void cache_set_flush(struct closure *cl)
if (!IS_ERR_OR_NULL(c->gc_thread)) if (!IS_ERR_OR_NULL(c->gc_thread))
kthread_stop(c->gc_thread); kthread_stop(c->gc_thread);
if (!IS_ERR_OR_NULL(c->root)) if (!IS_ERR(c->root))
list_add(&c->root->list, &c->btree_cache); list_add(&c->root->list, &c->btree_cache);
/* /*
@ -2087,7 +2087,7 @@ static int run_cache_set(struct cache_set *c)
err = "cannot allocate new btree root"; err = "cannot allocate new btree root";
c->root = __bch_btree_node_alloc(c, NULL, 0, true, NULL); c->root = __bch_btree_node_alloc(c, NULL, 0, true, NULL);
if (IS_ERR_OR_NULL(c->root)) if (IS_ERR(c->root))
goto err; goto err;
mutex_lock(&c->root->write_lock); mutex_lock(&c->root->write_lock);
@ -2218,7 +2218,7 @@ void bch_cache_release(struct kobject *kobj)
put_page(virt_to_page(ca->sb_disk)); put_page(virt_to_page(ca->sb_disk));
if (!IS_ERR_OR_NULL(ca->bdev)) if (!IS_ERR_OR_NULL(ca->bdev))
blkdev_put(ca->bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); blkdev_put(ca->bdev, bcache_kobj);
kfree(ca); kfree(ca);
module_put(THIS_MODULE); module_put(THIS_MODULE);
@ -2359,7 +2359,7 @@ static int register_cache(struct cache_sb *sb, struct cache_sb_disk *sb_disk,
* call blkdev_put() to bdev in bch_cache_release(). So we * call blkdev_put() to bdev in bch_cache_release(). So we
* explicitly call blkdev_put() here. * explicitly call blkdev_put() here.
*/ */
blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); blkdev_put(bdev, bcache_kobj);
if (ret == -ENOMEM) if (ret == -ENOMEM)
err = "cache_alloc(): -ENOMEM"; err = "cache_alloc(): -ENOMEM";
else if (ret == -EPERM) else if (ret == -EPERM)
@ -2461,7 +2461,7 @@ static void register_bdev_worker(struct work_struct *work)
if (!dc) { if (!dc) {
fail = true; fail = true;
put_page(virt_to_page(args->sb_disk)); put_page(virt_to_page(args->sb_disk));
blkdev_put(args->bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); blkdev_put(args->bdev, bcache_kobj);
goto out; goto out;
} }
@ -2491,7 +2491,7 @@ static void register_cache_worker(struct work_struct *work)
if (!ca) { if (!ca) {
fail = true; fail = true;
put_page(virt_to_page(args->sb_disk)); put_page(virt_to_page(args->sb_disk));
blkdev_put(args->bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); blkdev_put(args->bdev, bcache_kobj);
goto out; goto out;
} }
@ -2558,9 +2558,8 @@ static ssize_t register_bcache(struct kobject *k, struct kobj_attribute *attr,
ret = -EINVAL; ret = -EINVAL;
err = "failed to open device"; err = "failed to open device";
bdev = blkdev_get_by_path(strim(path), bdev = blkdev_get_by_path(strim(path), BLK_OPEN_READ | BLK_OPEN_WRITE,
FMODE_READ|FMODE_WRITE|FMODE_EXCL, bcache_kobj, NULL);
sb);
if (IS_ERR(bdev)) { if (IS_ERR(bdev)) {
if (bdev == ERR_PTR(-EBUSY)) { if (bdev == ERR_PTR(-EBUSY)) {
dev_t dev; dev_t dev;
@ -2648,7 +2647,7 @@ async_done:
out_put_sb_page: out_put_sb_page:
put_page(virt_to_page(sb_disk)); put_page(virt_to_page(sb_disk));
out_blkdev_put: out_blkdev_put:
blkdev_put(bdev, FMODE_READ | FMODE_WRITE | FMODE_EXCL); blkdev_put(bdev, register_bcache);
out_free_sb: out_free_sb:
kfree(sb); kfree(sb);
out_free_path: out_free_path:

View file

@ -1111,26 +1111,25 @@ SHOW(__bch_cache)
vfree(p); vfree(p);
ret = scnprintf(buf, PAGE_SIZE, ret = sysfs_emit(buf,
"Unused: %zu%%\n" "Unused: %zu%%\n"
"Clean: %zu%%\n" "Clean: %zu%%\n"
"Dirty: %zu%%\n" "Dirty: %zu%%\n"
"Metadata: %zu%%\n" "Metadata: %zu%%\n"
"Average: %llu\n" "Average: %llu\n"
"Sectors per Q: %zu\n" "Sectors per Q: %zu\n"
"Quantiles: [", "Quantiles: [",
unused * 100 / (size_t) ca->sb.nbuckets, unused * 100 / (size_t) ca->sb.nbuckets,
available * 100 / (size_t) ca->sb.nbuckets, available * 100 / (size_t) ca->sb.nbuckets,
dirty * 100 / (size_t) ca->sb.nbuckets, dirty * 100 / (size_t) ca->sb.nbuckets,
meta * 100 / (size_t) ca->sb.nbuckets, sum, meta * 100 / (size_t) ca->sb.nbuckets, sum,
n * ca->sb.bucket_size / (ARRAY_SIZE(q) + 1)); n * ca->sb.bucket_size / (ARRAY_SIZE(q) + 1));
for (i = 0; i < ARRAY_SIZE(q); i++) for (i = 0; i < ARRAY_SIZE(q); i++)
ret += scnprintf(buf + ret, PAGE_SIZE - ret, ret += sysfs_emit_at(buf, ret, "%u ", q[i]);
"%u ", q[i]);
ret--; ret--;
ret += scnprintf(buf + ret, PAGE_SIZE - ret, "]\n"); ret += sysfs_emit_at(buf, ret, "]\n");
return ret; return ret;
} }

View file

@ -3,7 +3,7 @@
#define _BCACHE_SYSFS_H_ #define _BCACHE_SYSFS_H_
#define KTYPE(type) \ #define KTYPE(type) \
struct kobj_type type ## _ktype = { \ const struct kobj_type type ## _ktype = { \
.release = type ## _release, \ .release = type ## _release, \
.sysfs_ops = &((const struct sysfs_ops) { \ .sysfs_ops = &((const struct sysfs_ops) { \
.show = type ## _show, \ .show = type ## _show, \

View file

@ -890,6 +890,16 @@ static int bch_root_node_dirty_init(struct cache_set *c,
if (ret < 0) if (ret < 0)
pr_warn("sectors dirty init failed, ret=%d!\n", ret); pr_warn("sectors dirty init failed, ret=%d!\n", ret);
/*
* The op may be added to cache_set's btree_cache_wait
* in mca_cannibalize(), must ensure it is removed from
* the list and release btree_cache_alloc_lock before
* free op memory.
* Otherwise, the btree_cache_wait will be damaged.
*/
bch_cannibalize_unlock(c);
finish_wait(&c->btree_cache_wait, &(&op.op)->wait);
return ret; return ret;
} }

View file

@ -2051,8 +2051,8 @@ static int parse_metadata_dev(struct cache_args *ca, struct dm_arg_set *as,
if (!at_least_one_arg(as, error)) if (!at_least_one_arg(as, error))
return -EINVAL; return -EINVAL;
r = dm_get_device(ca->ti, dm_shift_arg(as), FMODE_READ | FMODE_WRITE, r = dm_get_device(ca->ti, dm_shift_arg(as),
&ca->metadata_dev); BLK_OPEN_READ | BLK_OPEN_WRITE, &ca->metadata_dev);
if (r) { if (r) {
*error = "Error opening metadata device"; *error = "Error opening metadata device";
return r; return r;
@ -2074,8 +2074,8 @@ static int parse_cache_dev(struct cache_args *ca, struct dm_arg_set *as,
if (!at_least_one_arg(as, error)) if (!at_least_one_arg(as, error))
return -EINVAL; return -EINVAL;
r = dm_get_device(ca->ti, dm_shift_arg(as), FMODE_READ | FMODE_WRITE, r = dm_get_device(ca->ti, dm_shift_arg(as),
&ca->cache_dev); BLK_OPEN_READ | BLK_OPEN_WRITE, &ca->cache_dev);
if (r) { if (r) {
*error = "Error opening cache device"; *error = "Error opening cache device";
return r; return r;
@ -2093,8 +2093,8 @@ static int parse_origin_dev(struct cache_args *ca, struct dm_arg_set *as,
if (!at_least_one_arg(as, error)) if (!at_least_one_arg(as, error))
return -EINVAL; return -EINVAL;
r = dm_get_device(ca->ti, dm_shift_arg(as), FMODE_READ | FMODE_WRITE, r = dm_get_device(ca->ti, dm_shift_arg(as),
&ca->origin_dev); BLK_OPEN_READ | BLK_OPEN_WRITE, &ca->origin_dev);
if (r) { if (r) {
*error = "Error opening origin device"; *error = "Error opening origin device";
return r; return r;

View file

@ -1683,8 +1683,8 @@ static int parse_metadata_dev(struct clone *clone, struct dm_arg_set *as, char *
int r; int r;
sector_t metadata_dev_size; sector_t metadata_dev_size;
r = dm_get_device(clone->ti, dm_shift_arg(as), FMODE_READ | FMODE_WRITE, r = dm_get_device(clone->ti, dm_shift_arg(as),
&clone->metadata_dev); BLK_OPEN_READ | BLK_OPEN_WRITE, &clone->metadata_dev);
if (r) { if (r) {
*error = "Error opening metadata device"; *error = "Error opening metadata device";
return r; return r;
@ -1703,8 +1703,8 @@ static int parse_dest_dev(struct clone *clone, struct dm_arg_set *as, char **err
int r; int r;
sector_t dest_dev_size; sector_t dest_dev_size;
r = dm_get_device(clone->ti, dm_shift_arg(as), FMODE_READ | FMODE_WRITE, r = dm_get_device(clone->ti, dm_shift_arg(as),
&clone->dest_dev); BLK_OPEN_READ | BLK_OPEN_WRITE, &clone->dest_dev);
if (r) { if (r) {
*error = "Error opening destination device"; *error = "Error opening destination device";
return r; return r;
@ -1725,7 +1725,7 @@ static int parse_source_dev(struct clone *clone, struct dm_arg_set *as, char **e
int r; int r;
sector_t source_dev_size; sector_t source_dev_size;
r = dm_get_device(clone->ti, dm_shift_arg(as), FMODE_READ, r = dm_get_device(clone->ti, dm_shift_arg(as), BLK_OPEN_READ,
&clone->source_dev); &clone->source_dev);
if (r) { if (r) {
*error = "Error opening source device"; *error = "Error opening source device";

View file

@ -207,11 +207,10 @@ struct dm_table {
unsigned integrity_added:1; unsigned integrity_added:1;
/* /*
* Indicates the rw permissions for the new logical * Indicates the rw permissions for the new logical device. This
* device. This should be a combination of FMODE_READ * should be a combination of BLK_OPEN_READ and BLK_OPEN_WRITE.
* and FMODE_WRITE.
*/ */
fmode_t mode; blk_mode_t mode;
/* a list of devices used by this table */ /* a list of devices used by this table */
struct list_head devices; struct list_head devices;

View file

@ -1693,8 +1693,7 @@ retry:
len = (remaining_size > PAGE_SIZE) ? PAGE_SIZE : remaining_size; len = (remaining_size > PAGE_SIZE) ? PAGE_SIZE : remaining_size;
bio_add_page(clone, page, len, 0); __bio_add_page(clone, page, len, 0);
remaining_size -= len; remaining_size -= len;
} }

View file

@ -1482,14 +1482,16 @@ static int era_ctr(struct dm_target *ti, unsigned int argc, char **argv)
era->ti = ti; era->ti = ti;
r = dm_get_device(ti, argv[0], FMODE_READ | FMODE_WRITE, &era->metadata_dev); r = dm_get_device(ti, argv[0], BLK_OPEN_READ | BLK_OPEN_WRITE,
&era->metadata_dev);
if (r) { if (r) {
ti->error = "Error opening metadata device"; ti->error = "Error opening metadata device";
era_destroy(era); era_destroy(era);
return -EINVAL; return -EINVAL;
} }
r = dm_get_device(ti, argv[1], FMODE_READ | FMODE_WRITE, &era->origin_dev); r = dm_get_device(ti, argv[1], BLK_OPEN_READ | BLK_OPEN_WRITE,
&era->origin_dev);
if (r) { if (r) {
ti->error = "Error opening data device"; ti->error = "Error opening data device";
era_destroy(era); era_destroy(era);

View file

@ -293,8 +293,10 @@ static int __init dm_init_init(void)
for (i = 0; i < ARRAY_SIZE(waitfor); i++) { for (i = 0; i < ARRAY_SIZE(waitfor); i++) {
if (waitfor[i]) { if (waitfor[i]) {
dev_t dev;
DMINFO("waiting for device %s ...", waitfor[i]); DMINFO("waiting for device %s ...", waitfor[i]);
while (!dm_get_dev_t(waitfor[i])) while (early_lookup_bdev(waitfor[i], &dev))
fsleep(5000); fsleep(5000);
} }
} }

View file

@ -861,7 +861,7 @@ static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
table = dm_get_inactive_table(md, &srcu_idx); table = dm_get_inactive_table(md, &srcu_idx);
if (table) { if (table) {
if (!(dm_table_get_mode(table) & FMODE_WRITE)) if (!(dm_table_get_mode(table) & BLK_OPEN_WRITE))
param->flags |= DM_READONLY_FLAG; param->flags |= DM_READONLY_FLAG;
param->target_count = table->num_targets; param->target_count = table->num_targets;
} }
@ -1189,7 +1189,7 @@ static int do_resume(struct dm_ioctl *param)
if (old_size && new_size && old_size != new_size) if (old_size && new_size && old_size != new_size)
need_resize_uevent = true; need_resize_uevent = true;
if (dm_table_get_mode(new_map) & FMODE_WRITE) if (dm_table_get_mode(new_map) & BLK_OPEN_WRITE)
set_disk_ro(dm_disk(md), 0); set_disk_ro(dm_disk(md), 0);
else else
set_disk_ro(dm_disk(md), 1); set_disk_ro(dm_disk(md), 1);
@ -1378,12 +1378,12 @@ static int dev_arm_poll(struct file *filp, struct dm_ioctl *param, size_t param_
return 0; return 0;
} }
static inline fmode_t get_mode(struct dm_ioctl *param) static inline blk_mode_t get_mode(struct dm_ioctl *param)
{ {
fmode_t mode = FMODE_READ | FMODE_WRITE; blk_mode_t mode = BLK_OPEN_READ | BLK_OPEN_WRITE;
if (param->flags & DM_READONLY_FLAG) if (param->flags & DM_READONLY_FLAG)
mode = FMODE_READ; mode = BLK_OPEN_READ;
return mode; return mode;
} }

View file

@ -3750,11 +3750,11 @@ static int raid_message(struct dm_target *ti, unsigned int argc, char **argv,
* canceling read-auto mode * canceling read-auto mode
*/ */
mddev->ro = 0; mddev->ro = 0;
if (!mddev->suspended && mddev->sync_thread) if (!mddev->suspended)
md_wakeup_thread(mddev->sync_thread); md_wakeup_thread(mddev->sync_thread);
} }
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
if (!mddev->suspended && mddev->thread) if (!mddev->suspended)
md_wakeup_thread(mddev->thread); md_wakeup_thread(mddev->thread);
return 0; return 0;

View file

@ -1241,9 +1241,8 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
int i; int i;
int r = -EINVAL; int r = -EINVAL;
char *origin_path, *cow_path; char *origin_path, *cow_path;
dev_t origin_dev, cow_dev;
unsigned int args_used, num_flush_bios = 1; unsigned int args_used, num_flush_bios = 1;
fmode_t origin_mode = FMODE_READ; blk_mode_t origin_mode = BLK_OPEN_READ;
if (argc < 4) { if (argc < 4) {
ti->error = "requires 4 or more arguments"; ti->error = "requires 4 or more arguments";
@ -1253,7 +1252,7 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
if (dm_target_is_snapshot_merge(ti)) { if (dm_target_is_snapshot_merge(ti)) {
num_flush_bios = 2; num_flush_bios = 2;
origin_mode = FMODE_WRITE; origin_mode = BLK_OPEN_WRITE;
} }
s = kzalloc(sizeof(*s), GFP_KERNEL); s = kzalloc(sizeof(*s), GFP_KERNEL);
@ -1279,24 +1278,21 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
ti->error = "Cannot get origin device"; ti->error = "Cannot get origin device";
goto bad_origin; goto bad_origin;
} }
origin_dev = s->origin->bdev->bd_dev;
cow_path = argv[0]; cow_path = argv[0];
argv++; argv++;
argc--; argc--;
cow_dev = dm_get_dev_t(cow_path);
if (cow_dev && cow_dev == origin_dev) {
ti->error = "COW device cannot be the same as origin device";
r = -EINVAL;
goto bad_cow;
}
r = dm_get_device(ti, cow_path, dm_table_get_mode(ti->table), &s->cow); r = dm_get_device(ti, cow_path, dm_table_get_mode(ti->table), &s->cow);
if (r) { if (r) {
ti->error = "Cannot get COW device"; ti->error = "Cannot get COW device";
goto bad_cow; goto bad_cow;
} }
if (s->cow->bdev && s->cow->bdev == s->origin->bdev) {
ti->error = "COW device cannot be the same as origin device";
r = -EINVAL;
goto bad_store;
}
r = dm_exception_store_create(ti, argc, argv, s, &args_used, &s->store); r = dm_exception_store_create(ti, argc, argv, s, &args_used, &s->store);
if (r) { if (r) {

View file

@ -126,7 +126,7 @@ static int alloc_targets(struct dm_table *t, unsigned int num)
return 0; return 0;
} }
int dm_table_create(struct dm_table **result, fmode_t mode, int dm_table_create(struct dm_table **result, blk_mode_t mode,
unsigned int num_targets, struct mapped_device *md) unsigned int num_targets, struct mapped_device *md)
{ {
struct dm_table *t = kzalloc(sizeof(*t), GFP_KERNEL); struct dm_table *t = kzalloc(sizeof(*t), GFP_KERNEL);
@ -304,7 +304,7 @@ static int device_area_is_invalid(struct dm_target *ti, struct dm_dev *dev,
* device and not to touch the existing bdev field in case * device and not to touch the existing bdev field in case
* it is accessed concurrently. * it is accessed concurrently.
*/ */
static int upgrade_mode(struct dm_dev_internal *dd, fmode_t new_mode, static int upgrade_mode(struct dm_dev_internal *dd, blk_mode_t new_mode,
struct mapped_device *md) struct mapped_device *md)
{ {
int r; int r;
@ -323,24 +323,14 @@ static int upgrade_mode(struct dm_dev_internal *dd, fmode_t new_mode,
return 0; return 0;
} }
/*
* Convert the path to a device
*/
dev_t dm_get_dev_t(const char *path)
{
dev_t dev;
if (lookup_bdev(path, &dev))
dev = name_to_dev_t(path);
return dev;
}
EXPORT_SYMBOL_GPL(dm_get_dev_t);
/* /*
* Add a device to the list, or just increment the usage count if * Add a device to the list, or just increment the usage count if
* it's already present. * it's already present.
*
* Note: the __ref annotation is because this function can call the __init
* marked early_lookup_bdev when called during early boot code from dm-init.c.
*/ */
int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode, int __ref dm_get_device(struct dm_target *ti, const char *path, blk_mode_t mode,
struct dm_dev **result) struct dm_dev **result)
{ {
int r; int r;
@ -358,9 +348,13 @@ int dm_get_device(struct dm_target *ti, const char *path, fmode_t mode,
if (MAJOR(dev) != major || MINOR(dev) != minor) if (MAJOR(dev) != major || MINOR(dev) != minor)
return -EOVERFLOW; return -EOVERFLOW;
} else { } else {
dev = dm_get_dev_t(path); r = lookup_bdev(path, &dev);
if (!dev) #ifndef MODULE
return -ENODEV; if (r && system_state < SYSTEM_RUNNING)
r = early_lookup_bdev(path, &dev);
#endif
if (r)
return r;
} }
if (dev == disk_devt(t->md->disk)) if (dev == disk_devt(t->md->disk))
return -EINVAL; return -EINVAL;
@ -668,7 +662,8 @@ int dm_table_add_target(struct dm_table *t, const char *type,
t->singleton = true; t->singleton = true;
} }
if (dm_target_always_writeable(ti->type) && !(t->mode & FMODE_WRITE)) { if (dm_target_always_writeable(ti->type) &&
!(t->mode & BLK_OPEN_WRITE)) {
ti->error = "target type may not be included in a read-only table"; ti->error = "target type may not be included in a read-only table";
goto bad; goto bad;
} }
@ -2039,7 +2034,7 @@ struct list_head *dm_table_get_devices(struct dm_table *t)
return &t->devices; return &t->devices;
} }
fmode_t dm_table_get_mode(struct dm_table *t) blk_mode_t dm_table_get_mode(struct dm_table *t)
{ {
return t->mode; return t->mode;
} }

View file

@ -3300,7 +3300,7 @@ static int pool_ctr(struct dm_target *ti, unsigned int argc, char **argv)
unsigned long block_size; unsigned long block_size;
dm_block_t low_water_blocks; dm_block_t low_water_blocks;
struct dm_dev *metadata_dev; struct dm_dev *metadata_dev;
fmode_t metadata_mode; blk_mode_t metadata_mode;
/* /*
* FIXME Remove validation from scope of lock. * FIXME Remove validation from scope of lock.
@ -3333,7 +3333,8 @@ static int pool_ctr(struct dm_target *ti, unsigned int argc, char **argv)
if (r) if (r)
goto out_unlock; goto out_unlock;
metadata_mode = FMODE_READ | ((pf.mode == PM_READ_ONLY) ? 0 : FMODE_WRITE); metadata_mode = BLK_OPEN_READ |
((pf.mode == PM_READ_ONLY) ? 0 : BLK_OPEN_WRITE);
r = dm_get_device(ti, argv[0], metadata_mode, &metadata_dev); r = dm_get_device(ti, argv[0], metadata_mode, &metadata_dev);
if (r) { if (r) {
ti->error = "Error opening metadata block device"; ti->error = "Error opening metadata block device";
@ -3341,7 +3342,7 @@ static int pool_ctr(struct dm_target *ti, unsigned int argc, char **argv)
} }
warn_if_metadata_device_too_big(metadata_dev->bdev); warn_if_metadata_device_too_big(metadata_dev->bdev);
r = dm_get_device(ti, argv[1], FMODE_READ | FMODE_WRITE, &data_dev); r = dm_get_device(ti, argv[1], BLK_OPEN_READ | BLK_OPEN_WRITE, &data_dev);
if (r) { if (r) {
ti->error = "Error getting data device"; ti->error = "Error getting data device";
goto out_metadata; goto out_metadata;
@ -4222,7 +4223,7 @@ static int thin_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad_origin_dev; goto bad_origin_dev;
} }
r = dm_get_device(ti, argv[2], FMODE_READ, &origin_dev); r = dm_get_device(ti, argv[2], BLK_OPEN_READ, &origin_dev);
if (r) { if (r) {
ti->error = "Error opening origin device"; ti->error = "Error opening origin device";
goto bad_origin_dev; goto bad_origin_dev;

View file

@ -607,7 +607,7 @@ int verity_fec_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
(*argc)--; (*argc)--;
if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_DEV)) { if (!strcasecmp(arg_name, DM_VERITY_OPT_FEC_DEV)) {
r = dm_get_device(ti, arg_value, FMODE_READ, &v->fec->dev); r = dm_get_device(ti, arg_value, BLK_OPEN_READ, &v->fec->dev);
if (r) { if (r) {
ti->error = "FEC device lookup failed"; ti->error = "FEC device lookup failed";
return r; return r;

View file

@ -1196,7 +1196,7 @@ static int verity_ctr(struct dm_target *ti, unsigned int argc, char **argv)
if (r) if (r)
goto bad; goto bad;
if ((dm_table_get_mode(ti->table) & ~FMODE_READ)) { if ((dm_table_get_mode(ti->table) & ~BLK_OPEN_READ)) {
ti->error = "Device must be readonly"; ti->error = "Device must be readonly";
r = -EINVAL; r = -EINVAL;
goto bad; goto bad;
@ -1225,13 +1225,13 @@ static int verity_ctr(struct dm_target *ti, unsigned int argc, char **argv)
} }
v->version = num; v->version = num;
r = dm_get_device(ti, argv[1], FMODE_READ, &v->data_dev); r = dm_get_device(ti, argv[1], BLK_OPEN_READ, &v->data_dev);
if (r) { if (r) {
ti->error = "Data device lookup failed"; ti->error = "Data device lookup failed";
goto bad; goto bad;
} }
r = dm_get_device(ti, argv[2], FMODE_READ, &v->hash_dev); r = dm_get_device(ti, argv[2], BLK_OPEN_READ, &v->hash_dev);
if (r) { if (r) {
ti->error = "Hash device lookup failed"; ti->error = "Hash device lookup failed";
goto bad; goto bad;

View file

@ -577,7 +577,7 @@ static struct dmz_mblock *dmz_get_mblock_slow(struct dmz_metadata *zmd,
bio->bi_iter.bi_sector = dmz_blk2sect(block); bio->bi_iter.bi_sector = dmz_blk2sect(block);
bio->bi_private = mblk; bio->bi_private = mblk;
bio->bi_end_io = dmz_mblock_bio_end_io; bio->bi_end_io = dmz_mblock_bio_end_io;
bio_add_page(bio, mblk->page, DMZ_BLOCK_SIZE, 0); __bio_add_page(bio, mblk->page, DMZ_BLOCK_SIZE, 0);
submit_bio(bio); submit_bio(bio);
return mblk; return mblk;
@ -728,7 +728,7 @@ static int dmz_write_mblock(struct dmz_metadata *zmd, struct dmz_mblock *mblk,
bio->bi_iter.bi_sector = dmz_blk2sect(block); bio->bi_iter.bi_sector = dmz_blk2sect(block);
bio->bi_private = mblk; bio->bi_private = mblk;
bio->bi_end_io = dmz_mblock_bio_end_io; bio->bi_end_io = dmz_mblock_bio_end_io;
bio_add_page(bio, mblk->page, DMZ_BLOCK_SIZE, 0); __bio_add_page(bio, mblk->page, DMZ_BLOCK_SIZE, 0);
submit_bio(bio); submit_bio(bio);
return 0; return 0;
@ -752,7 +752,7 @@ static int dmz_rdwr_block(struct dmz_dev *dev, enum req_op op,
bio = bio_alloc(dev->bdev, 1, op | REQ_SYNC | REQ_META | REQ_PRIO, bio = bio_alloc(dev->bdev, 1, op | REQ_SYNC | REQ_META | REQ_PRIO,
GFP_NOIO); GFP_NOIO);
bio->bi_iter.bi_sector = dmz_blk2sect(block); bio->bi_iter.bi_sector = dmz_blk2sect(block);
bio_add_page(bio, page, DMZ_BLOCK_SIZE, 0); __bio_add_page(bio, page, DMZ_BLOCK_SIZE, 0);
ret = submit_bio_wait(bio); ret = submit_bio_wait(bio);
bio_put(bio); bio_put(bio);

View file

@ -310,13 +310,13 @@ int dm_deleting_md(struct mapped_device *md)
return test_bit(DMF_DELETING, &md->flags); return test_bit(DMF_DELETING, &md->flags);
} }
static int dm_blk_open(struct block_device *bdev, fmode_t mode) static int dm_blk_open(struct gendisk *disk, blk_mode_t mode)
{ {
struct mapped_device *md; struct mapped_device *md;
spin_lock(&_minor_lock); spin_lock(&_minor_lock);
md = bdev->bd_disk->private_data; md = disk->private_data;
if (!md) if (!md)
goto out; goto out;
@ -334,7 +334,7 @@ out:
return md ? 0 : -ENXIO; return md ? 0 : -ENXIO;
} }
static void dm_blk_close(struct gendisk *disk, fmode_t mode) static void dm_blk_close(struct gendisk *disk)
{ {
struct mapped_device *md; struct mapped_device *md;
@ -448,7 +448,7 @@ static void dm_unprepare_ioctl(struct mapped_device *md, int srcu_idx)
dm_put_live_table(md, srcu_idx); dm_put_live_table(md, srcu_idx);
} }
static int dm_blk_ioctl(struct block_device *bdev, fmode_t mode, static int dm_blk_ioctl(struct block_device *bdev, blk_mode_t mode,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
struct mapped_device *md = bdev->bd_disk->private_data; struct mapped_device *md = bdev->bd_disk->private_data;
@ -734,7 +734,7 @@ static char *_dm_claim_ptr = "I belong to device-mapper";
* Open a table device so we can use it as a map destination. * Open a table device so we can use it as a map destination.
*/ */
static struct table_device *open_table_device(struct mapped_device *md, static struct table_device *open_table_device(struct mapped_device *md,
dev_t dev, fmode_t mode) dev_t dev, blk_mode_t mode)
{ {
struct table_device *td; struct table_device *td;
struct block_device *bdev; struct block_device *bdev;
@ -746,7 +746,7 @@ static struct table_device *open_table_device(struct mapped_device *md,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
refcount_set(&td->count, 1); refcount_set(&td->count, 1);
bdev = blkdev_get_by_dev(dev, mode | FMODE_EXCL, _dm_claim_ptr); bdev = blkdev_get_by_dev(dev, mode, _dm_claim_ptr, NULL);
if (IS_ERR(bdev)) { if (IS_ERR(bdev)) {
r = PTR_ERR(bdev); r = PTR_ERR(bdev);
goto out_free_td; goto out_free_td;
@ -771,7 +771,7 @@ static struct table_device *open_table_device(struct mapped_device *md,
return td; return td;
out_blkdev_put: out_blkdev_put:
blkdev_put(bdev, mode | FMODE_EXCL); blkdev_put(bdev, _dm_claim_ptr);
out_free_td: out_free_td:
kfree(td); kfree(td);
return ERR_PTR(r); return ERR_PTR(r);
@ -784,14 +784,14 @@ static void close_table_device(struct table_device *td, struct mapped_device *md
{ {
if (md->disk->slave_dir) if (md->disk->slave_dir)
bd_unlink_disk_holder(td->dm_dev.bdev, md->disk); bd_unlink_disk_holder(td->dm_dev.bdev, md->disk);
blkdev_put(td->dm_dev.bdev, td->dm_dev.mode | FMODE_EXCL); blkdev_put(td->dm_dev.bdev, _dm_claim_ptr);
put_dax(td->dm_dev.dax_dev); put_dax(td->dm_dev.dax_dev);
list_del(&td->list); list_del(&td->list);
kfree(td); kfree(td);
} }
static struct table_device *find_table_device(struct list_head *l, dev_t dev, static struct table_device *find_table_device(struct list_head *l, dev_t dev,
fmode_t mode) blk_mode_t mode)
{ {
struct table_device *td; struct table_device *td;
@ -802,7 +802,7 @@ static struct table_device *find_table_device(struct list_head *l, dev_t dev,
return NULL; return NULL;
} }
int dm_get_table_device(struct mapped_device *md, dev_t dev, fmode_t mode, int dm_get_table_device(struct mapped_device *md, dev_t dev, blk_mode_t mode,
struct dm_dev **result) struct dm_dev **result)
{ {
struct table_device *td; struct table_device *td;

View file

@ -203,7 +203,7 @@ int dm_open_count(struct mapped_device *md);
int dm_lock_for_deletion(struct mapped_device *md, bool mark_deferred, bool only_deferred); int dm_lock_for_deletion(struct mapped_device *md, bool mark_deferred, bool only_deferred);
int dm_cancel_deferred_remove(struct mapped_device *md); int dm_cancel_deferred_remove(struct mapped_device *md);
int dm_request_based(struct mapped_device *md); int dm_request_based(struct mapped_device *md);
int dm_get_table_device(struct mapped_device *md, dev_t dev, fmode_t mode, int dm_get_table_device(struct mapped_device *md, dev_t dev, blk_mode_t mode,
struct dm_dev **result); struct dm_dev **result);
void dm_put_table_device(struct mapped_device *md, struct dm_dev *d); void dm_put_table_device(struct mapped_device *md, struct dm_dev *d);

Some files were not shown because too many files have changed in this diff Show more