diff options
author | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2020-05-19 23:01:26 +0200 |
---|---|---|
committer | Marcel Ziswiler <marcel.ziswiler@toradex.com> | 2020-05-19 23:37:01 +0200 |
commit | 2ae782ca839e0ee07de37122ddea362adff2e975 (patch) | |
tree | df6b1a190760f51465122ca4c13492d5ac5984c6 /drivers/block | |
parent | 0a8ab17689e628c84a666195bfc6ab85d11cf057 (diff) | |
parent | 0661b3d6cfd774e28a2e2ba90a3d87479e5c399b (diff) |
Merge tag 'v4.9.220' into 4.9-2.3.x-imx
This is the 4.9.220 stable release
Conflicts:
arch/arm/Kconfig.debug
arch/arm/boot/dts/imx7s.dtsi
arch/arm/mach-imx/common.h
arch/arm/mach-imx/cpuidle-imx6q.c
arch/arm/mach-imx/cpuidle-imx6sx.c
arch/arm/mach-imx/suspend-imx6.S
block/blk-core.c
drivers/crypto/caam/caamalg.c
drivers/crypto/mxs-dcp.c
drivers/dma/imx-sdma.c
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
drivers/input/keyboard/imx_keypad.c
drivers/input/keyboard/snvs_pwrkey.c
drivers/mmc/host/sdhci.c
drivers/net/can/flexcan.c
drivers/net/ethernet/freescale/fec_main.c
drivers/net/phy/phy_device.c
drivers/net/wireless/ath/ath10k/pci.c
drivers/tty/serial/imx.c
drivers/usb/dwc3/gadget.c
drivers/usb/host/xhci.c
include/linux/blkdev.h
include/linux/cpu.h
include/linux/platform_data/dma-imx-sdma.h
kernel/cpu.c
net/wireless/util.c
sound/soc/fsl/Kconfig
sound/soc/fsl/fsl_esai.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/imx-sgtl5000.c
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/amiflop.c | 84 | ||||
-rw-r--r-- | drivers/block/brd.c | 22 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 3 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_nl.c | 43 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 66 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_state.h | 2 | ||||
-rw-r--r-- | drivers/block/floppy.c | 369 | ||||
-rw-r--r-- | drivers/block/loop.c | 43 | ||||
-rw-r--r-- | drivers/block/loop.h | 1 | ||||
-rw-r--r-- | drivers/block/rsxx/core.c | 2 | ||||
-rw-r--r-- | drivers/block/virtio_blk.c | 10 | ||||
-rw-r--r-- | drivers/block/xen-blkback/blkback.c | 2 | ||||
-rw-r--r-- | drivers/block/xen-blkback/xenbus.c | 16 | ||||
-rw-r--r-- | drivers/block/xen-blkfront.c | 4 | ||||
-rw-r--r-- | drivers/block/xsysace.c | 2 |
15 files changed, 572 insertions, 97 deletions
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 5fd50a284168..db4354fb2a0d 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -1699,11 +1699,41 @@ static const struct block_device_operations floppy_fops = { .check_events = amiga_check_events, }; +static struct gendisk *fd_alloc_disk(int drive) +{ + struct gendisk *disk; + + disk = alloc_disk(1); + if (!disk) + goto out; + + disk->queue = blk_init_queue(do_fd_request, &amiflop_lock); + if (IS_ERR(disk->queue)) { + disk->queue = NULL; + goto out_put_disk; + } + + unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL); + if (!unit[drive].trackbuf) + goto out_cleanup_queue; + + return disk; + +out_cleanup_queue: + blk_cleanup_queue(disk->queue); + disk->queue = NULL; +out_put_disk: + put_disk(disk); +out: + unit[drive].type->code = FD_NODRIVE; + return NULL; +} + static int __init fd_probe_drives(void) { int drive,drives,nomem; - printk(KERN_INFO "FD: probing units\nfound "); + pr_info("FD: probing units\nfound"); drives=0; nomem=0; for(drive=0;drive<FD_MAX_UNITS;drive++) { @@ -1711,27 +1741,17 @@ static int __init fd_probe_drives(void) fd_probe(drive); if (unit[drive].type->code == FD_NODRIVE) continue; - disk = alloc_disk(1); + + disk = fd_alloc_disk(drive); if (!disk) { - unit[drive].type->code = FD_NODRIVE; + pr_cont(" no mem for fd%d", drive); + nomem = 1; continue; } unit[drive].gendisk = disk; - - disk->queue = blk_init_queue(do_fd_request, &amiflop_lock); - if (!disk->queue) { - unit[drive].type->code = FD_NODRIVE; - continue; - } - drives++; - if ((unit[drive].trackbuf = kmalloc(FLOPPY_MAX_SECTORS * 512, GFP_KERNEL)) == NULL) { - printk("no mem for "); - unit[drive].type = &drive_types[num_dr_types - 1]; /* FD_NODRIVE */ - drives--; - nomem = 1; - } - printk("fd%d ",drive); + + pr_cont(" fd%d",drive); disk->major = FLOPPY_MAJOR; disk->first_minor = drive; disk->fops = &floppy_fops; @@ -1742,11 +1762,11 @@ static int __init fd_probe_drives(void) } if ((drives > 0) || (nomem == 0)) { if (drives == 0) - printk("no drives"); - printk("\n"); + pr_cont(" no drives"); + pr_cont("\n"); return drives; } - printk("\n"); + pr_cont("\n"); return -ENOMEM; } @@ -1837,30 +1857,6 @@ out_blkdev: return ret; } -#if 0 /* not safe to unload */ -static int __exit amiga_floppy_remove(struct platform_device *pdev) -{ - int i; - - for( i = 0; i < FD_MAX_UNITS; i++) { - if (unit[i].type->code != FD_NODRIVE) { - struct request_queue *q = unit[i].gendisk->queue; - del_gendisk(unit[i].gendisk); - put_disk(unit[i].gendisk); - kfree(unit[i].trackbuf); - if (q) - blk_cleanup_queue(q); - } - } - blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256); - free_irq(IRQ_AMIGA_CIAA_TB, NULL); - free_irq(IRQ_AMIGA_DSKBLK, NULL); - custom.dmacon = DMAF_DISK; /* disable DMA */ - amiga_chip_free(raw_buf); - unregister_blkdev(FLOPPY_MAJOR, "fd"); -} -#endif - static struct platform_driver amiga_floppy_driver = { .driver = { .name = "amiga-floppy", diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 0c76d4016eeb..7e35574a17df 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -581,6 +581,25 @@ static struct kobject *brd_probe(dev_t dev, int *part, void *data) return kobj; } +static inline void brd_check_and_reset_par(void) +{ + if (unlikely(!max_part)) + max_part = 1; + + /* + * make sure 'max_part' can be divided exactly by (1U << MINORBITS), + * otherwise, it is possiable to get same dev_t when adding partitions. + */ + if ((1U << MINORBITS) % max_part != 0) + max_part = 1UL << fls(max_part); + + if (max_part > DISK_MAX_PARTS) { + pr_info("brd: max_part can't be larger than %d, reset max_part = %d.\n", + DISK_MAX_PARTS, DISK_MAX_PARTS); + max_part = DISK_MAX_PARTS; + } +} + static int __init brd_init(void) { struct brd_device *brd, *next; @@ -604,8 +623,7 @@ static int __init brd_init(void) if (register_blkdev(RAMDISK_MAJOR, "ramdisk")) return -EIO; - if (unlikely(!max_part)) - max_part = 1; + brd_check_and_reset_par(); for (i = 0; i < rd_nr; i++) { brd = brd_alloc(i); diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 83482721bc01..daa9cef96ec6 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c @@ -332,6 +332,8 @@ static int drbd_thread_setup(void *arg) thi->name[0], resource->name); + allow_kernel_signal(DRBD_SIGKILL); + allow_kernel_signal(SIGXCPU); restart: retval = thi->function(thi); @@ -793,7 +795,6 @@ int __drbd_send_protocol(struct drbd_connection *connection, enum drbd_packet cm if (nc->tentative && connection->agreed_pro_version < 92) { rcu_read_unlock(); - mutex_unlock(&sock->mutex); drbd_err(connection, "--dry-run is not supported by peer"); return -EOPNOTSUPP; } diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index abee91940a36..b809f325c2be 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1508,6 +1508,30 @@ static void sanitize_disk_conf(struct drbd_device *device, struct disk_conf *dis } } +static int disk_opts_check_al_size(struct drbd_device *device, struct disk_conf *dc) +{ + int err = -EBUSY; + + if (device->act_log && + device->act_log->nr_elements == dc->al_extents) + return 0; + + drbd_suspend_io(device); + /* If IO completion is currently blocked, we would likely wait + * "forever" for the activity log to become unused. So we don't. */ + if (atomic_read(&device->ap_bio_cnt)) + goto out; + + wait_event(device->al_wait, lc_try_lock(device->act_log)); + drbd_al_shrink(device); + err = drbd_check_al_size(device, dc); + lc_unlock(device->act_log); + wake_up(&device->al_wait); +out: + drbd_resume_io(device); + return err; +} + int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info) { struct drbd_config_context adm_ctx; @@ -1570,15 +1594,12 @@ int drbd_adm_disk_opts(struct sk_buff *skb, struct genl_info *info) } } - drbd_suspend_io(device); - wait_event(device->al_wait, lc_try_lock(device->act_log)); - drbd_al_shrink(device); - err = drbd_check_al_size(device, new_disk_conf); - lc_unlock(device->act_log); - wake_up(&device->al_wait); - drbd_resume_io(device); - + err = disk_opts_check_al_size(device, new_disk_conf); if (err) { + /* Could be just "busy". Ignore? + * Introduce dedicated error code? */ + drbd_msg_put_info(adm_ctx.reply_skb, + "Try again without changing current al-extents setting"); retcode = ERR_NOMEM; goto fail_unlock; } @@ -1927,9 +1948,9 @@ int drbd_adm_attach(struct sk_buff *skb, struct genl_info *info) } } - if (device->state.conn < C_CONNECTED && - device->state.role == R_PRIMARY && device->ed_uuid && - (device->ed_uuid & ~((u64)1)) != (nbc->md.uuid[UI_CURRENT] & ~((u64)1))) { + if (device->state.pdsk != D_UP_TO_DATE && device->ed_uuid && + (device->state.role == R_PRIMARY || device->state.peer == R_PRIMARY) && + (device->ed_uuid & ~((u64)1)) != (nbc->md.uuid[UI_CURRENT] & ~((u64)1))) { drbd_err(device, "Can only attach to data with current UUID=%016llX\n", (unsigned long long)device->ed_uuid); retcode = ERR_DATA_NOT_CURRENT; diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 83957a1e15ed..a10ff6e8c20b 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c @@ -4037,6 +4037,7 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info struct o_qlim *o = (connection->agreed_features & DRBD_FF_WSAME) ? p->qlim : NULL; enum determine_dev_size dd = DS_UNCHANGED; sector_t p_size, p_usize, p_csize, my_usize; + sector_t new_size, cur_size; int ldsc = 0; /* local disk size changed */ enum dds_flags ddsf; @@ -4044,6 +4045,7 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info if (!peer_device) return config_unknown_volume(connection, pi); device = peer_device->device; + cur_size = drbd_get_capacity(device->this_bdev); p_size = be64_to_cpu(p->d_size); p_usize = be64_to_cpu(p->u_size); @@ -4054,7 +4056,6 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info device->p_size = p_size; if (get_ldev(device)) { - sector_t new_size, cur_size; rcu_read_lock(); my_usize = rcu_dereference(device->ldev->disk_conf)->disk_size; rcu_read_unlock(); @@ -4072,7 +4073,6 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info /* Never shrink a device with usable data during connect. But allow online shrinking if we are connected. */ new_size = drbd_new_dev_size(device, device->ldev, p_usize, 0); - cur_size = drbd_get_capacity(device->this_bdev); if (new_size < cur_size && device->state.disk >= D_OUTDATED && device->state.conn < C_CONNECTED) { @@ -4137,9 +4137,36 @@ static int receive_sizes(struct drbd_connection *connection, struct packet_info * * However, if he sends a zero current size, * take his (user-capped or) backing disk size anyways. + * + * Unless of course he does not have a disk himself. + * In which case we ignore this completely. */ + sector_t new_size = p_csize ?: p_usize ?: p_size; drbd_reconsider_queue_parameters(device, NULL, o); - drbd_set_my_capacity(device, p_csize ?: p_usize ?: p_size); + if (new_size == 0) { + /* Ignore, peer does not know nothing. */ + } else if (new_size == cur_size) { + /* nothing to do */ + } else if (cur_size != 0 && p_size == 0) { + drbd_warn(device, "Ignored diskless peer device size (peer:%llu != me:%llu sectors)!\n", + (unsigned long long)new_size, (unsigned long long)cur_size); + } else if (new_size < cur_size && device->state.role == R_PRIMARY) { + drbd_err(device, "The peer's device size is too small! (%llu < %llu sectors); demote me first!\n", + (unsigned long long)new_size, (unsigned long long)cur_size); + conn_request_state(peer_device->connection, NS(conn, C_DISCONNECTING), CS_HARD); + return -EIO; + } else { + /* I believe the peer, if + * - I don't have a current size myself + * - we agree on the size anyways + * - I do have a current size, am Secondary, + * and he has the only disk + * - I do have a current size, am Primary, + * and he has the only disk, + * which is larger than my current size + */ + drbd_set_my_capacity(device, new_size); + } } if (get_ldev(device)) { @@ -4425,6 +4452,25 @@ static int receive_state(struct drbd_connection *connection, struct packet_info if (peer_state.conn == C_AHEAD) ns.conn = C_BEHIND; + /* TODO: + * if (primary and diskless and peer uuid != effective uuid) + * abort attach on peer; + * + * If this node does not have good data, was already connected, but + * the peer did a late attach only now, trying to "negotiate" with me, + * AND I am currently Primary, possibly frozen, with some specific + * "effective" uuid, this should never be reached, really, because + * we first send the uuids, then the current state. + * + * In this scenario, we already dropped the connection hard + * when we received the unsuitable uuids (receive_uuids(). + * + * Should we want to change this, that is: not drop the connection in + * receive_uuids() already, then we would need to add a branch here + * that aborts the attach of "unsuitable uuids" on the peer in case + * this node is currently Diskless Primary. + */ + if (device->p_uuid && peer_state.disk >= D_NEGOTIATING && get_ldev_if_state(device, D_NEGOTIATING)) { int cr; /* consider resync */ @@ -5297,7 +5343,7 @@ static int drbd_do_auth(struct drbd_connection *connection) unsigned int key_len; char secret[SHARED_SECRET_MAX]; /* 64 byte */ unsigned int resp_size; - SHASH_DESC_ON_STACK(desc, connection->cram_hmac_tfm); + struct shash_desc *desc; struct packet_info pi; struct net_conf *nc; int err, rv; @@ -5310,6 +5356,13 @@ static int drbd_do_auth(struct drbd_connection *connection) memcpy(secret, nc->shared_secret, key_len); rcu_read_unlock(); + desc = kmalloc(sizeof(struct shash_desc) + + crypto_shash_descsize(connection->cram_hmac_tfm), + GFP_KERNEL); + if (!desc) { + rv = -1; + goto fail; + } desc->tfm = connection->cram_hmac_tfm; desc->flags = 0; @@ -5452,7 +5505,10 @@ static int drbd_do_auth(struct drbd_connection *connection) kfree(peers_ch); kfree(response); kfree(right_response); - shash_desc_zero(desc); + if (desc) { + shash_desc_zero(desc); + kfree(desc); + } return rv; } diff --git a/drivers/block/drbd/drbd_state.h b/drivers/block/drbd/drbd_state.h index 6c9d5d4a8a75..110f64d9e91c 100644 --- a/drivers/block/drbd/drbd_state.h +++ b/drivers/block/drbd/drbd_state.h @@ -126,7 +126,7 @@ extern enum drbd_state_rv _drbd_set_state(struct drbd_device *, union drbd_state enum chg_state_flags, struct completion *done); extern void print_st_err(struct drbd_device *, union drbd_state, - union drbd_state, int); + union drbd_state, enum drbd_state_rv); enum drbd_state_rv _conn_request_state(struct drbd_connection *connection, union drbd_state mask, union drbd_state val, diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 6914c6e1e1a8..4496e7a49235 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -192,6 +192,7 @@ static int print_unex = 1; #include <linux/io.h> #include <linux/uaccess.h> #include <linux/async.h> +#include <linux/compat.h> /* * PS/2 floppies have much slower step rates than regular floppies. @@ -847,14 +848,17 @@ static void reset_fdc_info(int mode) /* selects the fdc and drive, and enables the fdc's input/dma. */ static void set_fdc(int drive) { + unsigned int new_fdc = fdc; + if (drive >= 0 && drive < N_DRIVE) { - fdc = FDC(drive); + new_fdc = FDC(drive); current_drive = drive; } - if (fdc != 1 && fdc != 0) { + if (new_fdc >= N_FDC) { pr_info("bad fdc value\n"); return; } + fdc = new_fdc; set_dor(fdc, ~0, 8); #if N_FDC > 1 set_dor(1 - fdc, ~8, 0); @@ -2113,6 +2117,9 @@ static void setup_format_params(int track) raw_cmd->kernel_data = floppy_track_buffer; raw_cmd->length = 4 * F_SECT_PER_TRACK; + if (!F_SECT_PER_TRACK) + return; + /* allow for about 30ms for data transport per track */ head_shift = (F_SECT_PER_TRACK + 5) / 6; @@ -3233,8 +3240,12 @@ static int set_geometry(unsigned int cmd, struct floppy_struct *g, int cnt; /* sanity checking for parameters. */ - if (g->sect <= 0 || - g->head <= 0 || + if ((int)g->sect <= 0 || + (int)g->head <= 0 || + /* check for overflow in max_sector */ + (int)(g->sect * g->head) <= 0 || + /* check for zero in F_SECT_PER_TRACK */ + (unsigned char)((g->sect << 2) >> FD_SIZECODE(g)) == 0 || g->track <= 0 || g->track > UDP->tracks >> STRETCH(g) || /* check if reserved bits are set */ (g->stretch & ~(FD_STRETCH | FD_SWAPSIDES | FD_SECTBASEMASK)) != 0) @@ -3378,6 +3389,24 @@ static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo) return 0; } +static bool valid_floppy_drive_params(const short autodetect[8], + int native_format) +{ + size_t floppy_type_size = ARRAY_SIZE(floppy_type); + size_t i = 0; + + for (i = 0; i < 8; ++i) { + if (autodetect[i] < 0 || + autodetect[i] >= floppy_type_size) + return false; + } + + if (native_format < 0 || native_format >= floppy_type_size) + return false; + + return true; +} + static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, unsigned long param) { @@ -3504,6 +3533,9 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int SUPBOUND(size, strlen((const char *)outparam) + 1); break; case FDSETDRVPRM: + if (!valid_floppy_drive_params(inparam.dp.autodetect, + inparam.dp.native_format)) + return -EINVAL; *UDP = inparam.dp; break; case FDGETDRVPRM: @@ -3569,6 +3601,332 @@ static int fd_ioctl(struct block_device *bdev, fmode_t mode, return ret; } +#ifdef CONFIG_COMPAT + +struct compat_floppy_drive_params { + char cmos; + compat_ulong_t max_dtr; + compat_ulong_t hlt; + compat_ulong_t hut; + compat_ulong_t srt; + compat_ulong_t spinup; + compat_ulong_t spindown; + unsigned char spindown_offset; + unsigned char select_delay; + unsigned char rps; + unsigned char tracks; + compat_ulong_t timeout; + unsigned char interleave_sect; + struct floppy_max_errors max_errors; + char flags; + char read_track; + short autodetect[8]; + compat_int_t checkfreq; + compat_int_t native_format; +}; + +struct compat_floppy_drive_struct { + signed char flags; + compat_ulong_t spinup_date; + compat_ulong_t select_date; + compat_ulong_t first_read_date; + short probed_format; + short track; + short maxblock; + short maxtrack; + compat_int_t generation; + compat_int_t keep_data; + compat_int_t fd_ref; + compat_int_t fd_device; + compat_int_t last_checked; + compat_caddr_t dmabuf; + compat_int_t bufblocks; +}; + +struct compat_floppy_fdc_state { + compat_int_t spec1; + compat_int_t spec2; + compat_int_t dtr; + unsigned char version; + unsigned char dor; + compat_ulong_t address; + unsigned int rawcmd:2; + unsigned int reset:1; + unsigned int need_configure:1; + unsigned int perp_mode:2; + unsigned int has_fifo:1; + unsigned int driver_version; + unsigned char track[4]; +}; + +struct compat_floppy_write_errors { + unsigned int write_errors; + compat_ulong_t first_error_sector; + compat_int_t first_error_generation; + compat_ulong_t last_error_sector; + compat_int_t last_error_generation; + compat_uint_t badness; +}; + +#define FDSETPRM32 _IOW(2, 0x42, struct compat_floppy_struct) +#define FDDEFPRM32 _IOW(2, 0x43, struct compat_floppy_struct) +#define FDSETDRVPRM32 _IOW(2, 0x90, struct compat_floppy_drive_params) +#define FDGETDRVPRM32 _IOR(2, 0x11, struct compat_floppy_drive_params) +#define FDGETDRVSTAT32 _IOR(2, 0x12, struct compat_floppy_drive_struct) +#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct compat_floppy_drive_struct) +#define FDGETFDCSTAT32 _IOR(2, 0x15, struct compat_floppy_fdc_state) +#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, + struct compat_floppy_struct __user *arg) +{ + struct floppy_struct v; + int drive, type; + int err; + + BUILD_BUG_ON(offsetof(struct floppy_struct, name) != + offsetof(struct compat_floppy_struct, name)); + + if (!(mode & (FMODE_WRITE | FMODE_WRITE_IOCTL))) + return -EPERM; + + memset(&v, 0, sizeof(struct floppy_struct)); + if (copy_from_user(&v, arg, offsetof(struct floppy_struct, name))) + return -EFAULT; + + mutex_lock(&floppy_mutex); + drive = (long)bdev->bd_disk->private_data; + type = ITYPE(UDRS->fd_device); + err = set_geometry(cmd == FDSETPRM32 ? FDSETPRM : FDDEFPRM, + &v, drive, type, bdev); + mutex_unlock(&floppy_mutex); + return err; +} + +static int compat_get_prm(int drive, + struct compat_floppy_struct __user *arg) +{ + struct compat_floppy_struct v; + struct floppy_struct *p; + int err; + + memset(&v, 0, sizeof(v)); + mutex_lock(&floppy_mutex); + err = get_floppy_geometry(drive, ITYPE(UDRS->fd_device), &p); + if (err) { + mutex_unlock(&floppy_mutex); + return err; + } + memcpy(&v, p, offsetof(struct floppy_struct, name)); + mutex_unlock(&floppy_mutex); + if (copy_to_user(arg, &v, sizeof(struct compat_floppy_struct))) + return -EFAULT; + return 0; +} + +static int compat_setdrvprm(int drive, + struct compat_floppy_drive_params __user *arg) +{ + struct compat_floppy_drive_params v; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + if (copy_from_user(&v, arg, sizeof(struct compat_floppy_drive_params))) + return -EFAULT; + if (!valid_floppy_drive_params(v.autodetect, v.native_format)) + return -EINVAL; + mutex_lock(&floppy_mutex); + UDP->cmos = v.cmos; + UDP->max_dtr = v.max_dtr; + UDP->hlt = v.hlt; + UDP->hut = v.hut; + UDP->srt = v.srt; + UDP->spinup = v.spinup; + UDP->spindown = v.spindown; + UDP->spindown_offset = v.spindown_offset; + UDP->select_delay = v.select_delay; + UDP->rps = v.rps; + UDP->tracks = v.tracks; + UDP->timeout = v.timeout; + UDP->interleave_sect = v.interleave_sect; + UDP->max_errors = v.max_errors; + UDP->flags = v.flags; + UDP->read_track = v.read_track; + memcpy(UDP->autodetect, v.autodetect, sizeof(v.autodetect)); + UDP->checkfreq = v.checkfreq; + UDP->native_format = v.native_format; + mutex_unlock(&floppy_mutex); + return 0; +} + +static int compat_getdrvprm(int drive, + struct compat_floppy_drive_params __user *arg) +{ + struct compat_floppy_drive_params v; + + memset(&v, 0, sizeof(struct compat_floppy_drive_params)); + mutex_lock(&floppy_mutex); + v.cmos = UDP->cmos; + v.max_dtr = UDP->max_dtr; + v.hlt = UDP->hlt; + v.hut = UDP->hut; + v.srt = UDP->srt; + v.spinup = UDP->spinup; + v.spindown = UDP->spindown; + v.spindown_offset = UDP->spindown_offset; + v.select_delay = UDP->select_delay; + v.rps = UDP->rps; + v.tracks = UDP->tracks; + v.timeout = UDP->timeout; + v.interleave_sect = UDP->interleave_sect; + v.max_errors = UDP->max_errors; + v.flags = UDP->flags; + v.read_track = UDP->read_track; + memcpy(v.autodetect, UDP->autodetect, sizeof(v.autodetect)); + v.checkfreq = UDP->checkfreq; + v.native_format = UDP->native_format; + mutex_unlock(&floppy_mutex); + + if (copy_to_user(arg, &v, sizeof(struct compat_floppy_drive_params))) + return -EFAULT; + return 0; +} + +static int compat_getdrvstat(int drive, bool poll, + struct compat_floppy_drive_struct __user *arg) +{ + struct compat_floppy_drive_struct v; + + memset(&v, 0, sizeof(struct compat_floppy_drive_struct)); + mutex_lock(&floppy_mutex); + + if (poll) { + if (lock_fdc(drive)) + goto Eintr; + if (poll_drive(true, FD_RAW_NEED_DISK) == -EINTR) + goto Eintr; + process_fd_request(); + } + v.spinup_date = UDRS->spinup_date; + v.select_date = UDRS->select_date; + v.first_read_date = UDRS->first_read_date; + v.probed_format = UDRS->probed_format; + v.track = UDRS->track; + v.maxblock = UDRS->maxblock; + v.maxtrack = UDRS->maxtrack; + v.generation = UDRS->generation; + v.keep_data = UDRS->keep_data; + v.fd_ref = UDRS->fd_ref; + v.fd_device = UDRS->fd_device; + v.last_checked = UDRS->last_checked; + v.dmabuf = (uintptr_t)UDRS->dmabuf; + v.bufblocks = UDRS->bufblocks; + mutex_unlock(&floppy_mutex); + + if (copy_to_user(arg, &v, sizeof(struct compat_floppy_drive_struct))) + return -EFAULT; + return 0; +Eintr: + mutex_unlock(&floppy_mutex); + return -EINTR; +} + +static int compat_getfdcstat(int drive, + struct compat_floppy_fdc_state __user *arg) +{ + struct compat_floppy_fdc_state v32; + struct floppy_fdc_state v; + + mutex_lock(&floppy_mutex); + v = *UFDCS; + mutex_unlock(&floppy_mutex); + + memset(&v32, 0, sizeof(struct compat_floppy_fdc_state)); + v32.spec1 = v.spec1; + v32.spec2 = v.spec2; + v32.dtr = v.dtr; + v32.version = v.version; + v32.dor = v.dor; + v32.address = v.address; + v32.rawcmd = v.rawcmd; + v32.reset = v.reset; + v32.need_configure = v.need_configure; + v32.perp_mode = v.perp_mode; + v32.has_fifo = v.has_fifo; + v32.driver_version = v.driver_version; + memcpy(v32.track, v.track, 4); + if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_fdc_state))) + return -EFAULT; + return 0; +} + +static int compat_werrorget(int drive, + struct compat_floppy_write_errors __user *arg) +{ + struct compat_floppy_write_errors v32; + struct floppy_write_errors v; + + memset(&v32, 0, sizeof(struct compat_floppy_write_errors)); + mutex_lock(&floppy_mutex); + v = *UDRWE; + mutex_unlock(&floppy_mutex); + v32.write_errors = v.write_errors; + v32.first_error_sector = v.first_error_sector; + v32.first_error_generation = v.first_error_generation; + v32.last_error_sector = v.last_error_sector; + v32.last_error_generation = v.last_error_generation; + v32.badness = v.badness; + if (copy_to_user(arg, &v32, sizeof(struct compat_floppy_write_errors))) + return -EFAULT; + return 0; +} + +static int fd_compat_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd, + unsigned long param) +{ + int drive = (long)bdev->bd_disk->private_data; + switch (cmd) { + case FDMSGON: + case FDMSGOFF: + case FDSETEMSGTRESH: + case FDFLUSH: + case FDWERRORCLR: + case FDEJECT: + case FDCLRPRM: + case FDFMTBEG: + case FDRESET: + case FDTWADDLE: + return fd_ioctl(bdev, mode, cmd, param); + case FDSETMAXERRS: + case FDGETMAXERRS: + case FDGETDRVTYP: + case FDFMTEND: + case FDFMTTRK: + case FDRAWCMD: + return fd_ioctl(bdev, mode, cmd, + (unsigned long)compat_ptr(param)); + case FDSETPRM32: + case FDDEFPRM32: + return compat_set_geometry(bdev, mode, cmd, compat_ptr(param)); + case FDGETPRM32: + return compat_get_prm(drive, compat_ptr(param)); + case FDSETDRVPRM32: + return compat_setdrvprm(drive, compat_ptr(param)); + case FDGETDRVPRM32: + return compat_getdrvprm(drive, compat_ptr(param)); + case FDPOLLDRVSTAT32: + return compat_getdrvstat(drive, true, compat_ptr(param)); + case FDGETDRVSTAT32: + return compat_getdrvstat(drive, false, compat_ptr(param)); + case FDGETFDCSTAT32: + return compat_getfdcstat(drive, compat_ptr(param)); + case FDWERRORGET32: + return compat_werrorget(drive, compat_ptr(param)); + } + return -EINVAL; +} +#endif + static void __init config_types(void) { bool has_drive = false; @@ -3891,6 +4249,9 @@ static const struct block_device_operations floppy_fops = { .getgeo = fd_getgeo, .check_events = floppy_check_events, .revalidate_disk = floppy_revalidate, +#ifdef CONFIG_COMPAT + .compat_ioctl = fd_compat_ioctl, +#endif }; /* diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 28ce17405aab..f236b7984b94 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -82,7 +82,6 @@ static DEFINE_IDR(loop_index_idr); static DEFINE_MUTEX(loop_index_mutex); -static DEFINE_MUTEX(loop_ctl_mutex); static int max_part; static int part_shift; @@ -1034,7 +1033,7 @@ static int loop_clr_fd(struct loop_device *lo) */ if (atomic_read(&lo->lo_refcnt) > 1) { lo->lo_flags |= LO_FLAGS_AUTOCLEAR; - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); return 0; } @@ -1083,12 +1082,12 @@ static int loop_clr_fd(struct loop_device *lo) if (!part_shift) lo->lo_disk->flags |= GENHD_FL_NO_PART_SCAN; loop_unprepare_queue(lo); - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); /* - * Need not hold loop_ctl_mutex to fput backing file. - * Calling fput holding loop_ctl_mutex triggers a circular + * Need not hold lo_ctl_mutex to fput backing file. + * Calling fput holding lo_ctl_mutex triggers a circular * lock dependency possibility warning as fput can take - * bd_mutex which is usually taken before loop_ctl_mutex. + * bd_mutex which is usually taken before lo_ctl_mutex. */ fput(filp); return 0; @@ -1351,7 +1350,7 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, struct loop_device *lo = bdev->bd_disk->private_data; int err; - mutex_lock_nested(&loop_ctl_mutex, 1); + mutex_lock_nested(&lo->lo_ctl_mutex, 1); switch (cmd) { case LOOP_SET_FD: err = loop_set_fd(lo, mode, bdev, arg); @@ -1360,7 +1359,7 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, err = loop_change_fd(lo, bdev, arg); break; case LOOP_CLR_FD: - /* loop_clr_fd would have unlocked loop_ctl_mutex on success */ + /* loop_clr_fd would have unlocked lo_ctl_mutex on success */ err = loop_clr_fd(lo); if (!err) goto out_unlocked; @@ -1396,7 +1395,7 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode, default: err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL; } - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); out_unlocked: return err; @@ -1529,16 +1528,16 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode, switch(cmd) { case LOOP_SET_STATUS: - mutex_lock(&loop_ctl_mutex); + mutex_lock(&lo->lo_ctl_mutex); err = loop_set_status_compat( lo, (const struct compat_loop_info __user *) arg); - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); break; case LOOP_GET_STATUS: - mutex_lock(&loop_ctl_mutex); + mutex_lock(&lo->lo_ctl_mutex); err = loop_get_status_compat( lo, (struct compat_loop_info __user *) arg); - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); break; case LOOP_SET_CAPACITY: case LOOP_CLR_FD: @@ -1547,6 +1546,7 @@ static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode, arg = (unsigned long) compat_ptr(arg); case LOOP_SET_FD: case LOOP_CHANGE_FD: + case LOOP_SET_DIRECT_IO: err = lo_ioctl(bdev, mode, cmd, arg); break; default: @@ -1582,7 +1582,7 @@ static void __lo_release(struct loop_device *lo) if (atomic_dec_return(&lo->lo_refcnt)) return; - mutex_lock(&loop_ctl_mutex); + mutex_lock(&lo->lo_ctl_mutex); if (lo->lo_flags & LO_FLAGS_AUTOCLEAR) { /* * In autoclear mode, stop the loop thread @@ -1599,7 +1599,7 @@ static void __lo_release(struct loop_device *lo) loop_flush(lo); } - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); } static void lo_release(struct gendisk *disk, fmode_t mode) @@ -1645,10 +1645,10 @@ static int unregister_transfer_cb(int id, void *ptr, void *data) struct loop_device *lo = ptr; struct loop_func_table *xfer = data; - mutex_lock(&loop_ctl_mutex); + mutex_lock(&lo->lo_ctl_mutex); if (lo->lo_encryption == xfer) loop_release_xfer(lo); - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); return 0; } @@ -1814,6 +1814,7 @@ static int loop_add(struct loop_device **l, int i) if (!part_shift) disk->flags |= GENHD_FL_NO_PART_SCAN; disk->flags |= GENHD_FL_EXT_DEVT; + mutex_init(&lo->lo_ctl_mutex); atomic_set(&lo->lo_refcnt, 0); lo->lo_number = i; spin_lock_init(&lo->lo_lock); @@ -1926,19 +1927,19 @@ static long loop_control_ioctl(struct file *file, unsigned int cmd, ret = loop_lookup(&lo, parm); if (ret < 0) break; - mutex_lock(&loop_ctl_mutex); + mutex_lock(&lo->lo_ctl_mutex); if (lo->lo_state != Lo_unbound) { ret = -EBUSY; - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); break; } if (atomic_read(&lo->lo_refcnt) > 0) { ret = -EBUSY; - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); break; } lo->lo_disk->private_data = NULL; - mutex_unlock(&loop_ctl_mutex); + mutex_unlock(&lo->lo_ctl_mutex); idr_remove(&loop_index_idr, lo->lo_number); loop_remove(lo); break; diff --git a/drivers/block/loop.h b/drivers/block/loop.h index a923e74495ce..60f0fd2c0c65 100644 --- a/drivers/block/loop.h +++ b/drivers/block/loop.h @@ -55,6 +55,7 @@ struct loop_device { spinlock_t lo_lock; int lo_state; + struct mutex lo_ctl_mutex; struct kthread_worker worker; struct task_struct *worker_task; bool use_dio; diff --git a/drivers/block/rsxx/core.c b/drivers/block/rsxx/core.c index 34997df132e2..6beafaa335c7 100644 --- a/drivers/block/rsxx/core.c +++ b/drivers/block/rsxx/core.c @@ -1025,8 +1025,10 @@ static void rsxx_pci_remove(struct pci_dev *dev) cancel_work_sync(&card->event_work); + destroy_workqueue(card->event_wq); rsxx_destroy_dev(card); rsxx_dma_destroy(card); + destroy_workqueue(card->creg_ctrl.creg_wq); spin_lock_irqsave(&card->irq_lock, flags); rsxx_disable_ier_and_isr(card, CR_INTR_ALL); diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index 10332c24f961..f287eec36b28 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -215,10 +215,12 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, err = __virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num); if (err) { virtqueue_kick(vblk->vqs[qid].vq); - blk_mq_stop_hw_queue(hctx); + /* Don't stop the queue if -ENOMEM: we may have failed to + * bounce the buffer due to global resource outage. + */ + if (err == -ENOSPC) + blk_mq_stop_hw_queue(hctx); spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags); - /* Out of mem doesn't actually happen, since we fall back - * to direct descriptors */ if (err == -ENOMEM || err == -ENOSPC) return BLK_MQ_RQ_QUEUE_BUSY; return BLK_MQ_RQ_QUEUE_ERROR; @@ -392,6 +394,8 @@ static int init_vq(struct virtio_blk *vblk) if (err) num_vqs = 1; + num_vqs = min_t(unsigned int, nr_cpu_ids, num_vqs); + vblk->vqs = kmalloc_array(num_vqs, sizeof(*vblk->vqs), GFP_KERNEL); if (!vblk->vqs) return -ENOMEM; diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c index d6eaaa25d1cc..a700e525535c 100644 --- a/drivers/block/xen-blkback/blkback.c +++ b/drivers/block/xen-blkback/blkback.c @@ -929,6 +929,8 @@ next: out_of_memory: pr_alert("%s: out of memory\n", __func__); put_free_pages(ring, pages_to_gnt, segs_to_map); + for (i = last_map; i < num; i++) + pages[i]->handle = BLKBACK_INVALID_HANDLE; return -ENOMEM; } diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c index 5dfe6e8af140..1d1f86657967 100644 --- a/drivers/block/xen-blkback/xenbus.c +++ b/drivers/block/xen-blkback/xenbus.c @@ -178,6 +178,15 @@ static struct xen_blkif *xen_blkif_alloc(domid_t domid) blkif->domid = domid; atomic_set(&blkif->refcnt, 1); init_completion(&blkif->drain_complete); + + /* + * Because freeing back to the cache may be deferred, it is not + * safe to unload the module (and hence destroy the cache) until + * this has completed. To prevent premature unloading, take an + * extra module reference here and release only when the object + * has been freed back to the cache. + */ + __module_get(THIS_MODULE); INIT_WORK(&blkif->free_work, xen_blkif_deferred_free); return blkif; @@ -322,6 +331,7 @@ static void xen_blkif_free(struct xen_blkif *blkif) /* Make sure everything is drained before shutting down */ kmem_cache_free(xen_blkif_cachep, blkif); + module_put(THIS_MODULE); } int __init xen_blkif_interface_init(void) @@ -967,6 +977,7 @@ static int read_per_ring_refs(struct xen_blkif_ring *ring, const char *dir) } blkif->nr_ring_pages = nr_grefs; + err = -ENOMEM; for (i = 0; i < nr_grefs * XEN_BLKIF_REQS_PER_PAGE; i++) { req = kzalloc(sizeof(*req), GFP_KERNEL); if (!req) @@ -989,7 +1000,7 @@ static int read_per_ring_refs(struct xen_blkif_ring *ring, const char *dir) err = xen_blkif_map(ring, ring_ref, nr_grefs, evtchn); if (err) { xenbus_dev_fatal(dev, err, "mapping ring-ref port %u", evtchn); - return err; + goto fail; } return 0; @@ -1009,8 +1020,7 @@ fail: } kfree(req); } - return -ENOMEM; - + return err; } static int connect_ring(struct backend_info *be) diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index c08ee8cf1e29..6ee3e928ebf1 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1104,8 +1104,8 @@ static int xlvbd_alloc_gendisk(blkif_sector_t capacity, if (!VDEV_IS_EXTENDED(info->vdevice)) { err = xen_translate_vdev(info->vdevice, &minor, &offset); if (err) - return err; - nr_parts = PARTS_PER_DISK; + return err; + nr_parts = PARTS_PER_DISK; } else { minor = BLKIF_MINOR_EXT(info->vdevice); nr_parts = PARTS_PER_EXT_DISK; diff --git a/drivers/block/xsysace.c b/drivers/block/xsysace.c index c4328d9d9981..f838119d12b2 100644 --- a/drivers/block/xsysace.c +++ b/drivers/block/xsysace.c @@ -1062,6 +1062,8 @@ static int ace_setup(struct ace_device *ace) return 0; err_read: + /* prevent double queue cleanup */ + ace->gd->queue = NULL; put_disk(ace->gd); err_alloc_disk: blk_cleanup_queue(ace->queue); |