4.14.171-stable review
Subsystems (3)
Greg Kroah-Hartman
maintainerPATCH 47/173 scsi: qla2xxx: Fix mtcp dump collection failure
In reply to Greg Kroah-HartmanFrom: Quinn Tran <[email protected]>
commit 641e0efddcbde52461e017136acd3ce7f2ef0c14 upstream.
MTCP dump failed due to MB Reg 10 was picking garbage data from stack memory.
--- drivers/scsi/qla2xxx/qla_mbx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/scsi/qla2xxx/qla_mbx.c +1 -2
@@ -5853,9 +5853,8 @@ qla2x00_dump_mctp_data(scsi_qla_host_t * mcp->mb[7 ] =LSW (MSD (req_dma)); mcp->mb[8 ] =MSW (addr);/* Setting RAM ID to valid */ - mcp->mb[10 ] |=BIT_7 ;/* For MCTP RAM ID is 0x40 */ - mcp->mb[10 ] |=0x40 ; + mcp->mb[10 ] =BIT_7 |0x40 ; mcp->out_mb |=MBX_10 |MBX_8 |MBX_7 |MBX_6 |MBX_5 |MBX_4 |MBX_3 |MBX_2 |MBX_1 |MBX_0 ;
Greg Kroah-Hartman
maintainerPATCH 48/173 power: supply: ltc2941-battery-gauge: fix use-after-free
In reply to Greg Kroah-HartmanFrom: Sven Van Asbroeck <[email protected]>
commit a60ec78d306c6548d4adbc7918b587a723c555cc upstream.
This driver's remove path calls cancel_delayed_work(). However, that function does not wait until the work function finishes. This could mean that the work function is still running after the driver's remove function has finished, which would result in a use-after-free.
Fix by calling cancel_delayed_work_sync(), which ensures that that the work is properly cancelled, no longer running, and unable to re-schedule itself.
This issue was detected with the help of Coccinelle.
--- drivers/power/supply/ltc2941-battery-gauge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/power/supply/ltc2941-battery-gauge.c +1 -1
@@ -406,7 +406,7 @@ static int ltc294x_i2c_remove(struct i2c {struct ltc294x_info *info =i2c_get_clientdata (client); -cancel_delayed_work (&info->work); +cancel_delayed_work_sync (&info->work);power_supply_unregister (info->supply);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 36/173 mmc: spi: Toggle SPI polarity, do not hardcode it
In reply to Greg Kroah-HartmanFrom: Linus Walleij <[email protected]>
commit af3ed119329cf9690598c5a562d95dfd128e91d6 upstream.
The code in mmc_spi_initsequence() tries to send a burst with high chipselect and for this reason hardcodes the device into SPI_CS_HIGH.
This is not good because the SPI_CS_HIGH flag indicates logical "asserted" CS not always the physical level. In some cases the signal is inverted in the GPIO library and in that case SPI_CS_HIGH is already set, and enforcing SPI_CS_HIGH again will actually drive it low.
Instead of hard-coding this, toggle the polarity so if the default is LOW it goes high to assert chipselect but if it is already high then toggle it low instead.
--- drivers/mmc/host/mmc_spi.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/mmc/host/mmc_spi.c +8 -3
@@ -1154,17 +1154,22 @@ static void mmc_spi_initsequence(struct* SPI protocol. Another is that when chipselect is released while * the card returns BUSY status, the clock must issue several cycles * with chipselect high before the card will stop driving its output. +* +* SPI_CS_HIGH means "asserted" here. In some cases like when using +* GPIOs for chip select, SPI_CS_HIGH is set but this will be logically +* inverted by gpiolib, so if we want to ascertain to drive it high +* we should toggle the default with an XOR as we do here. */ - host->spi->mode |=SPI_CS_HIGH ; + host->spi->mode ^=SPI_CS_HIGH ;if (spi_setup (host->spi) !=0 ) {/* Just warn; most cards work without it. */ dev_warn (&host->spi->dev,"can't change chip-select polarity\n" ); - host->spi->mode &= ~SPI_CS_HIGH ; + host->spi->mode ^=SPI_CS_HIGH ; }else {mmc_spi_readbytes (host,18 ); - host->spi->mode &= ~SPI_CS_HIGH ; + host->spi->mode ^=SPI_CS_HIGH ;if (spi_setup (host->spi) !=0 ) {/* Wot, we can't get the same setup we had before? */ dev_err(&host->spi->dev,
Greg Kroah-Hartman
maintainerPATCH 38/173 alarmtimer: Unregister wakeup source when module get fails
In reply to Greg Kroah-HartmanFrom: Stephen Boyd <[email protected]>
commit 6b6d188aae79a630957aefd88ff5c42af6553ee3 upstream.
The alarmtimer_rtc_add_device() function creates a wakeup source and then tries to grab a module reference. If that fails the function returns early with an error code, but fails to remove the wakeup source.
Cleanup this exit path so there is no dangling wakeup source, which is named 'alarmtime' left allocated which will conflict with another RTC device that may be registered later.
--- kernel/time/alarmtimer.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
kernel/time/alarmtimer.c +5 -3
@@ -91,6 +91,7 @@ static int alarmtimer_rtc_add_device(strunsigned long flags;struct rtc_device *rtc =to_rtc_device (dev);struct wakeup_source *__ws; +int ret =0 ;if (rtcdev)return -EBUSY ;
@@ -105,8 +106,8 @@ static int alarmtimer_rtc_add_device(strspin_lock_irqsave (&rtcdev_lock, flags);if (!rtcdev) {if (!try_module_get (rtc->owner)) { -spin_unlock_irqrestore (&rtcdev_lock, flags); -return -1 ; + ret =-1 ; + goto unlock; } rtcdev = rtc;
@@ -115,11 +116,12 @@ static int alarmtimer_rtc_add_device(str ws = __ws; __ws =NULL ; } +unlock:spin_unlock_irqrestore (&rtcdev_lock, flags);wakeup_source_unregister (__ws); -return 0 ; +return ret; }static inline void alarmtimer_rtc_timer_init (void )
Greg Kroah-Hartman
maintainerPATCH 62/173 samples/bpf: Dont try to remove users homedir on clean
In reply to Greg Kroah-HartmanFrom: Toke Høiland-Jørgensen <[email protected]>
commit b2e5e93ae8af6a34bca536cdc4b453ab1e707b8b upstream.
The 'clean' rule in the samples/bpf Makefile tries to remove backup files (ending in ~). However, if no such files exist, it will instead try to remove the user's home directory. While the attempt is mostly harmless, it does lead to a somewhat scary warning like this:
rm: cannot remove '~': Is a directory
Fix this by using find instead of shell expansion to locate any actual backup files that need to be removed.
--- samples/bpf/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
samples/bpf/Makefile +1 -1
@@ -184,7 +184,7 @@ all: $(LIBBPF) clean: $(MAKE) -C ../../ M=$(CURDIR) clean - @rm -f *~ + @find $(CURDIR) -type f -name '*~' -delete $(LIBBPF): FORCE $(MAKE) -C $(dir $@) $(notdir $@)
Greg Kroah-Hartman
maintainerPATCH 65/173 crypto: atmel-aes - Fix counter overflow in CTR mode
In reply to Greg Kroah-HartmanFrom: Tudor Ambarus <[email protected]>
commit 781a08d9740afa73357f1a60d45d7c93d7cca2dd upstream.
32 bit counter is not supported by neither of our AES IPs, all implement a 16 bit block counter. Drop the 32 bit block counter logic.
--- drivers/crypto/atmel-aes.c | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-)
drivers/crypto/atmel-aes.c +12 -25
@@ -91,7 +91,6 @@struct atmel_aes_caps {bool has_dualbuff;bool has_cfb64; -bool has_ctr32;bool has_gcm;bool has_xts;bool has_authenc;
@@ -990,8 +989,9 @@ static int atmel_aes_ctr_transfer(structstruct atmel_aes_ctr_ctx *ctx =atmel_aes_ctr_ctx_cast (dd->ctx);struct ablkcipher_request *req =ablkcipher_request_cast (dd->areq);struct scatterlist *src, *dst; -u32 ctr, blocks;size_t datalen; +u32 ctr; +u16 blocks, start, end;bool use_dma, fragmented = false;/* Check for transfer completion. */
@@ -1003,27 +1003,17 @@ static int atmel_aes_ctr_transfer(struct datalen = req->nbytes - ctx->offset; blocks =DIV_ROUND_UP (datalen,AES_BLOCK_SIZE ); ctr =be32_to_cpu (ctx->iv[3 ]); -if (dd->caps.has_ctr32) { -/* Check 32bit counter overflow. */ -u32 start = ctr; -u32 end = start + blocks -1 ; - -if (end < start) { - ctr |=0xffffffff ; - datalen =AES_BLOCK_SIZE * -start; - fragmented = true; - } - }else { -/* Check 16bit counter overflow. */ -u16 start = ctr &0xffff ; -u16 end = start + (u16 )blocks -1 ; - -if (blocks >>16 || end < start) { - ctr |=0xffff ; - datalen =AES_BLOCK_SIZE * (0x10000 -start); - fragmented = true; - } + +/* Check 16bit counter overflow. */ + start = ctr &0xffff ; + end = start + blocks -1 ; + +if (blocks >>16 || end < start) { + ctr |=0xffff ; + datalen =AES_BLOCK_SIZE * (0x10000 - start); + fragmented = true; } + use_dma = (datalen >=ATMEL_AES_DMA_THRESHOLD );/* Jump to offset. */
@@ -2536,7 +2526,6 @@ static void atmel_aes_get_cap(struct atm { dd->caps.has_dualbuff =0 ; dd->caps.has_cfb64 =0 ; - dd->caps.has_ctr32 =0 ; dd->caps.has_gcm =0 ; dd->caps.has_xts =0 ; dd->caps.has_authenc =0 ;
@@ -2547,7 +2536,6 @@ static void atmel_aes_get_cap(struct atmcase 0x500 : dd->caps.has_dualbuff =1 ; dd->caps.has_cfb64 =1 ; - dd->caps.has_ctr32 =1 ; dd->caps.has_gcm =1 ; dd->caps.has_xts =1 ; dd->caps.has_authenc =1 ;
@@ -2556,7 +2544,6 @@ static void atmel_aes_get_cap(struct atmcase 0x200 : dd->caps.has_dualbuff =1 ; dd->caps.has_cfb64 =1 ; - dd->caps.has_ctr32 =1 ; dd->caps.has_gcm =1 ; dd->caps.max_burst_size =4 ;break ;
Greg Kroah-Hartman
maintainerPATCH 68/173 scsi: qla2xxx: Fix unbound NVME response length
In reply to Greg Kroah-HartmanFrom: Arun Easi <[email protected]>
commit 00fe717ee1ea3c2979db4f94b1533c57aed8dea9 upstream.
On certain cases when response length is less than 32, NVME response data is supplied inline in IOCB. This is indicated by some combination of state flags. There was an instance when a high, and incorrect, response length was indicated causing driver to overrun buffers. Fix this by checking and limiting the response payload length.
--- drivers/scsi/qla2xxx/qla_dbg.c | 6 ------ drivers/scsi/qla2xxx/qla_dbg.h | 6 ++++++ drivers/scsi/qla2xxx/qla_isr.c | 12 ++++++++++++ 3 files changed, 18 insertions(+), 6 deletions(-)
drivers/scsi/qla2xxx/qla_dbg.c +0 -6
@@ -2517,12 +2517,6 @@ qla83xx_fw_dump_failed:/* Driver Debug Functions. */ /****************************************************************************/ -static inline int -ql_mask_match (uint32_t level) -{ -return (level & ql2xextended_error_logging) == level; -} -/* * This function is for formatting and logging debug information. * It is to be used when vha is available. It formats the message
drivers/scsi/qla2xxx/qla_dbg.h +6 -0
@@ -374,3 +374,9 @@ extern int qla24xx_dump_ram(struct qla_hextern void qla24xx_pause_risc (struct device_reg_24xx __iomem *,struct qla_hw_data *);extern int qla24xx_soft_reset (struct qla_hw_data *); + +static inline int +ql_mask_match (uint level) +{ +return (level & ql2xextended_error_logging) == level; +}
drivers/scsi/qla2xxx/qla_isr.c +12 -0
@@ -1853,6 +1853,18 @@ qla24xx_nvme_iocb_entry(scsi_qla_host_t inbuf = (uint32_t *)&sts->nvme_ersp_data; outbuf = (uint32_t *)fd->rspaddr; iocb->u.nvme.rsp_pyld_len =le16_to_cpu (sts->nvme_rsp_pyld_len); +if (unlikely (iocb->u.nvme.rsp_pyld_len > +sizeof (struct nvme_fc_ersp_iu ))) { +if (ql_mask_match (ql_dbg_io)) { +WARN_ONCE (1 ,"Unexpected response payload length %u.\n" , + iocb->u.nvme.rsp_pyld_len); +ql_log (ql_log_warn, fcport->vha,0x5100 , +"Unexpected response payload length %u.\n" , + iocb->u.nvme.rsp_pyld_len); + } + iocb->u.nvme.rsp_pyld_len = +sizeof (struct nvme_fc_ersp_iu ); + } iter = iocb->u.nvme.rsp_pyld_len >>2 ;for (; iter; iter--) *outbuf++ =swab32 (*inbuf++);
Greg Kroah-Hartman
maintainerPATCH 72/173 ARM: tegra: Enable PLLP bypass during Tegra124 LP1
In reply to Greg Kroah-HartmanFrom: Stephen Warren <[email protected]>
commit 1a3388d506bf5b45bb283e6a4c4706cfb4897333 upstream.
For a little over a year, U-Boot has configured the flow controller to perform automatic RAM re-repair on off->on power transitions of the CPU rail[1]. This is mandatory for correct operation of Tegra124. However, RAM re-repair relies on certain clocks, which the kernel must enable and leave running. PLLP is one of those clocks. This clock is shut down during LP1 in order to save power. Enable bypass (which I believe routes osc_div_clk, essentially the crystal clock, to the PLL output) so that this clock signal toggles even though the PLL is not active. This is required so that LP1 power mode (system suspend) operates correctly.
The bypass configuration must then be undone when resuming from LP1, so that all peripheral clocks run at the expected rate. Without this, many peripherals won't work correctly; for example, the UART baud rate would be incorrect.
NVIDIA's downstream kernel code only does this if not compiled for Tegra30, so the added code is made conditional upon the chip ID. NVIDIA's downstream code makes this change conditional upon the active CPU cluster. The upstream kernel currently doesn't support cluster switching, so this patch doesn't test the active CPU cluster ID.
[1] 3cc7942a4ae5 ARM: tegra: implement RAM repair
--- arch/arm/mach-tegra/sleep-tegra30.S | 11 +++++++++++ 1 file changed, 11 insertions(+)
arch/arm/mach-tegra/sleep-tegra30.S +11 -0
@@ -382,6 +382,14 @@ _pll_m_c_x_done: pll_locked r1, r0, CLK_RESET_PLLC_BASE pll_locked r1, r0, CLK_RESET_PLLX_BASE + tegra_get_soc_id TEGRA_APB_MISC_BASE, r1 + cmp r1, #TEGRA30 + beq 1f + ldr r1, [r0, #CLK_RESET_PLLP_BASE] + bic r1, r1, #(1<<31) @ disable PllP bypass + str r1, [r0, #CLK_RESET_PLLP_BASE] +1: + mov32 r7, TEGRA_TMRUS_BASE ldr r1, [r7] add r1, r1, #LOCK_DELAY
@@ -641,7 +649,10 @@ tegra30_switch_cpu_to_clk32k: str r0, [r4, #PMC_PLLP_WB0_OVERRIDE] /* disable PLLP, PLLA, PLLC and PLLX */ + tegra_get_soc_id TEGRA_APB_MISC_BASE, r1 + cmp r1, #TEGRA30 ldr r0, [r5, #CLK_RESET_PLLP_BASE] + orrne r0, r0, #(1 << 31) @ enable PllP bypass on fast cluster bic r0, r0, #(1 << 30) str r0, [r5, #CLK_RESET_PLLP_BASE] ldr r0, [r5, #CLK_RESET_PLLA_BASE]
Greg Kroah-Hartman
maintainerPATCH 106/173 nfsd: fix delay timer on 32-bit architectures
In reply to Greg Kroah-HartmanFrom: Arnd Bergmann <[email protected]>
commit 2561c92b12f4f4e386d453556685f75775c0938b upstream.
The nfsd4_cb_layout_done() function takes a 'time_t' value, multiplied by NSEC_PER_SEC*2 to get a nanosecond value.
This works fine on 64-bit architectures, but on 32-bit, any value over 1 second results in a signed integer overflow with unexpected results.
Cast one input to a 64-bit type in order to produce the same result that we have on 64-bit architectures, regarless of the type of nfsd4_lease.
--- fs/nfsd/nfs4layouts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfsd/nfs4layouts.c +1 -1
@@ -683,7 +683,7 @@ nfsd4_cb_layout_done(struct nfsd4_callba/* Client gets 2 lease periods to return it */ cutoff =ktime_add_ns (task->tk_start, - nn->nfsd4_lease *NSEC_PER_SEC *2 ); + (u64 )nn->nfsd4_lease *NSEC_PER_SEC *2 );if (ktime_before (now, cutoff)) {rpc_delay (task,HZ /100 );/* 10 mili-seconds */
Greg Kroah-Hartman
maintainerPATCH 92/173 clk: tegra: Mark fuse clock as critical
In reply to Greg Kroah-HartmanFrom: Stephen Warren <[email protected]>
commit bf83b96f87ae2abb1e535306ea53608e8de5dfbb upstream.
For a little over a year, U-Boot on Tegra124 has configured the flow controller to perform automatic RAM re-repair on off->on power transitions of the CPU rail[1]. This is mandatory for correct operation of Tegra124. However, RAM re-repair relies on certain clocks, which the kernel must enable and leave running. The fuse clock is one of those clocks. Mark this clock as critical so that LP1 power mode (system suspend) operates correctly.
[1] 3cc7942a4ae5 ARM: tegra: implement RAM repair
--- drivers/clk/tegra/clk-tegra-periph.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/clk/tegra/clk-tegra-periph.c +5 -1
@@ -825,7 +825,11 @@ static struct tegra_periph_init_data gatGATE ("vcp" ,"clk_m" ,29 ,0 , tegra_clk_vcp,0 ),GATE ("apbdma" ,"clk_m" ,34 ,0 , tegra_clk_apbdma,0 ),GATE ("kbc" ,"clk_32k" ,36 ,TEGRA_PERIPH_ON_APB |TEGRA_PERIPH_NO_RESET , tegra_clk_kbc,0 ), -GATE ("fuse" ,"clk_m" ,39 ,TEGRA_PERIPH_ON_APB , tegra_clk_fuse,0 ), +/* +* Critical for RAM re-repair operation, which must occur on resume +* from LP1 system suspend and as part of CCPLEX cluster switching. +*/ +GATE ("fuse" ,"clk_m" ,39 ,TEGRA_PERIPH_ON_APB , tegra_clk_fuse,CLK_IS_CRITICAL ),GATE ("fuse_burn" ,"clk_m" ,39 ,TEGRA_PERIPH_ON_APB , tegra_clk_fuse_burn,0 ),GATE ("kfuse" ,"clk_m" ,40 ,TEGRA_PERIPH_ON_APB , tegra_clk_kfuse,0 ), GATE("apbif", "clk_m", 107, TEGRA_PERIPH_ON_APB, tegra_clk_apbif, 0),
Greg Kroah-Hartman
maintainerPATCH 114/173 net: systemport: Avoid RBUF stuck in Wake-on-LAN mode
In reply to Greg Kroah-HartmanFrom: Florian Fainelli <[email protected]>
[ Upstream commit 263a425a482fc495d6d3f9a29b9103a664c38b69 ]
After a number of suspend and resume cycles, it is possible for the RBUF to be stuck in Wake-on-LAN mode, despite the MPD enable bit being cleared which instructed the RBUF to exit that mode.
Avoid creating that problematic condition by clearing the RX_EN and TX_EN bits in the UniMAC prior to disable the Magic Packet Detector logic which is guaranteed to make the RBUF exit Wake-on-LAN mode.
--- drivers/net/ethernet/broadcom/bcmsysport.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/ethernet/broadcom/bcmsysport.c +3 -0
@@ -2329,6 +2329,9 @@ static int bcm_sysport_resume(struct devumac_reset (priv); +/* Disable the UniMAC RX/TX */ +umac_enable_set (priv,CMD_RX_EN |CMD_TX_EN ,0 ); +/* We may have been suspended and never received a WOL event that * would turn off MPD detection, take care of that now */
Greg Kroah-Hartman
maintainerPATCH 107/173 nfsd: fix jiffies/time_t mixup in LRU list
In reply to Greg Kroah-HartmanFrom: Arnd Bergmann <[email protected]>
commit 9594497f2c78993cb66b696122f7c65528ace985 upstream.
The nfsd4_blocked_lock->nbl_time timestamp is recorded in jiffies, but then compared to a CLOCK_REALTIME timestamp later on, which makes no sense.
For consistency with the other timestamps, change this to use a time_t.
This is a change in behavior, which may cause regressions, but the current code is not sensible. On a system with CONFIG_HZ=1000, the 'time_after((unsigned long)nbl->nbl_time, (unsigned long)cutoff))' check is false for roughly the first 18 days of uptime and then true for the next 49 days.
--- fs/nfsd/nfs4state.c | 2 +- fs/nfsd/state.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
fs/nfsd/nfs4state.c +1 -1
@@ -6040,7 +6040,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struc }if (fl_flags &FL_SLEEP ) { - nbl->nbl_time = jiffies; + nbl->nbl_time =get_seconds ();spin_lock (&nn->blocked_locks_lock);list_add_tail (&nbl->nbl_list, &lock_sop->lo_blocked);list_add_tail (&nbl->nbl_lru, &nn->blocked_locks_lru);
fs/nfsd/state.h +1 -1
@@ -591,7 +591,7 @@ static inline bool nfsd4_stateid_generatstruct nfsd4_blocked_lock {struct list_head nbl_list;struct list_head nbl_lru; -unsigned long nbl_time; +time_t nbl_time;struct file_lock nbl_lock;struct knfsd_fh nbl_fh;struct nfsd4_callback nbl_cb;
Greg Kroah-Hartman
maintainerPATCH 140/173 rxrpc: Fix service call disconnection
In reply to Greg Kroah-HartmanFrom: David Howells <[email protected]>
[ Upstream commit b39a934ec72fa2b5a74123891f25273a38378b90 ]
The recent patch that substituted a flag on an rxrpc_call for the connection pointer being NULL as an indication that a call was disconnected puts the set_bit in the wrong place for service calls. This is only a problem if a call is implicitly terminated by a new call coming in on the same connection channel instead of a terminating ACK packet.
In such a case, rxrpc_input_implicit_end_call() calls __rxrpc_disconnect_call(), which is now (incorrectly) setting the disconnection bit, meaning that when rxrpc_release_call() is later called, it doesn't call rxrpc_disconnect_call() and so the call isn't removed from the peer's error distribution list and the list gets corrupted.
KASAN finds the issue as an access after release on a call, but the position at which it occurs is confusing as it appears to be related to a different call (the call site is where the latter call is being removed from the error distribution list and either the next or pprev pointer points to a previously released call).
Fix this by moving the setting of the flag from __rxrpc_disconnect_call() to rxrpc_disconnect_call() in the same place that the connection pointer was being cleared.
--- net/rxrpc/conn_object.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
net/rxrpc/conn_object.c +1 -2
@@ -163,8 +163,6 @@ void __rxrpc_disconnect_call(struct rxrpc_connection *conn,_enter ("%d,%x" , conn->debug_id, call->cid); -set_bit (RXRPC_CALL_DISCONNECTED , &call->flags); -if (rcu_access_pointer (chan->call) == call) {/* Save the result of the call so that we can repeat it if necessary * through the channel, whilst disposing of the actual call record.
@@ -209,6 +207,7 @@ void rxrpc_disconnect_call(struct rxrpc_call *call)__rxrpc_disconnect_call (conn, call);spin_unlock (&conn->channel_lock); +set_bit (RXRPC_CALL_DISCONNECTED , &call->flags); conn->idle_timestamp = jiffies; }
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 136/173 KVM: s390: do not clobber registers during guest reset/store status
In reply to Greg Kroah-HartmanFrom: Christian Borntraeger <[email protected]>
[ Upstream commit 55680890ea78be0df5e1384989f1be835043c084 ]
The initial CPU reset clobbers the userspace fpc and the store status ioctl clobbers the guest acrs + fpr. As these calls are only done via ioctl (and not via vcpu_run), no CPU context is loaded, so we can (and must) act directly on the sync regs, not on the thread context.
--- arch/s390/kvm/kvm-s390.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
arch/s390/kvm/kvm-s390.c +2 -4
@@ -2384,9 +2384,7 @@ static void kvm_s390_vcpu_initial_reset(struct kvm_vcpu *vcpu)memset (vcpu->arch.sie_block->gcr,0 ,16 *sizeof (__u64)); vcpu->arch.sie_block->gcr[0 ] =0xE0UL ; vcpu->arch.sie_block->gcr[14 ] =0xC2000000UL ; -/* make sure the new fpc will be lazily loaded */ -save_fpu_regs (); - current->thread.fpu.fpc =0 ; + vcpu->run->s.regs.fpc =0 ; vcpu->arch.sie_block->gbea =1 ; vcpu->arch.sie_block->pp =0 ; vcpu->arch.sie_block->fpf &= ~FPF_BPBC ;
@@ -3753,7 +3751,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp, }case KVM_S390_STORE_STATUS : idx =srcu_read_lock (&vcpu->kvm->srcu); - r =kvm_s390_vcpu_store_status (vcpu, arg); + r =kvm_s390_store_status_unloaded (vcpu, arg);srcu_read_unlock (&vcpu->kvm->srcu, idx);break ;case KVM_S390_SET_INITIAL_PSW : {
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 160/173 KVM: arm/arm64: vgic-its: Fix restoration of unmapped collections
In reply to Greg Kroah-HartmanFrom: Eric Auger <[email protected]>
commit 8c58be34494b7f1b2adb446e2d8beeb90e5de65b upstream.
Saving/restoring an unmapped collection is a valid scenario. For example this happens if a MAPTI command was sent, featuring an unmapped collection. At the moment the CTE fails to be restored. Only compare against the number of online vcpus if the rdist base is set.
--- virt/kvm/arm/vgic/vgic-its.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
virt/kvm/arm/vgic/vgic-its.c +2 -1
@@ -2210,7 +2210,8 @@ static int vgic_its_restore_cte(struct v target_addr = (u32)(val >>KVM_ITS_CTE_RDBASE_SHIFT ); coll_id = val &KVM_ITS_CTE_ICID_MASK ; -if (target_addr >=atomic_read (&kvm->online_vcpus)) +if (target_addr !=COLLECTION_NOT_MAPPED && + target_addr >=atomic_read (&kvm->online_vcpus))return -EINVAL ; collection =find_collection (its, coll_id);
Greg Kroah-Hartman
maintainerPATCH 150/173 serial: uartps: Add a timeout to the tx empty wait
In reply to Greg Kroah-HartmanFrom: Shubhrajyoti Datta <[email protected]>
[ Upstream commit 277375b864e8147975b064b513f491e2a910e66a ]
In case the cable is not connected then the target gets into an infinite wait for tx empty.
Add a timeout to the tx empty wait.
--- drivers/tty/serial/xilinx_uartps.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
drivers/tty/serial/xilinx_uartps.c +10 -4
@@ -31,6 +31,7 @@#include <linux/of.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/iopoll.h> #define CDNS_UART_TTY_NAME "ttyPS"#define CDNS_UART_NAME "xuartps"
@@ -39,6 +40,7 @@#define CDNS_UART_NR_PORTS 2#define CDNS_UART_FIFO_SIZE 64/* FIFO size */ #define CDNS_UART_REGISTER_SPACE 0x1000 +#define TX_TIMEOUT 500000/* Rx Trigger level */ static int rx_trigger_level =56 ;
@@ -685,16 +687,20 @@ static void cdns_uart_set_termios(structunsigned int cval =0 ;unsigned int baud, minbaud, maxbaud;unsigned long flags; -unsigned int ctrl_reg, mode_reg; +unsigned int ctrl_reg, mode_reg, val; +int err;spin_lock_irqsave (&port->lock, flags);/* Wait for the transmit FIFO to empty before making changes */ if (!(readl (port->membase +CDNS_UART_CR ) &CDNS_UART_CR_TX_DIS )) { -while (!(readl (port->membase +CDNS_UART_SR ) & -CDNS_UART_SR_TXEMPTY )) { -cpu_relax (); + err =readl_poll_timeout (port->membase +CDNS_UART_SR , + val, (val &CDNS_UART_SR_TXEMPTY ), +1000 ,TX_TIMEOUT ); +if (err) { +dev_err (port->dev,"timed out waiting for tx empty" ); +return ; } }
Greg Kroah-Hartman
maintainerPATCH 165/173 crypto: atmel-sha - fix error handling when setting hmac key
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
commit b529f1983b2dcc46354f311feda92e07b6e9e2da upstream.
HMAC keys can be of any length, and atmel_sha_hmac_key_set() can only fail due to -ENOMEM. But atmel_sha_hmac_setkey() incorrectly treated any error as a "bad key length" error. Fix it to correctly propagate the -ENOMEM error code and not set any tfm result flags.
--- drivers/crypto/atmel-sha.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-)
drivers/crypto/atmel-sha.c +1 -6
@@ -1921,12 +1921,7 @@ static int atmel_sha_hmac_setkey(struct {struct atmel_sha_hmac_ctx *hmac =crypto_ahash_ctx (tfm); -if (atmel_sha_hmac_key_set (&hmac->hkey, key, keylen)) { -crypto_ahash_set_flags (tfm,CRYPTO_TFM_RES_BAD_KEY_LEN ); -return -EINVAL ; - } - -return 0 ; +return atmel_sha_hmac_key_set (&hmac->hkey, key, keylen); }static int atmel_sha_hmac_init (struct ahash_request *req)
Greg Kroah-Hartman
maintainerPATCH 17/173 rxrpc: Fix NULL pointer deref due to call->conn being cleared on disconnect
In reply to Greg Kroah-HartmanFrom: David Howells <[email protected]>
[ Upstream commit 5273a191dca65a675dc0bcf3909e59c6933e2831 ]
When a call is disconnected, the connection pointer from the call is cleared to make sure it isn't used again and to prevent further attempted transmission for the call. Unfortunately, there might be a daemon trying to use it at the same time to transmit a packet.
Fix this by keeping call->conn set, but setting a flag on the call to indicate disconnection instead.
Remove also the bits in the transmission functions where the conn pointer is checked and a ref taken under spinlock as this is now redundant.
--- net/rxrpc/ar-internal.h | 1 + net/rxrpc/call_object.c | 4 ++-- net/rxrpc/conn_client.c | 3 +-- net/rxrpc/conn_object.c | 4 ++-- net/rxrpc/output.c | 26 +++++++++----------------- 5 files changed, 15 insertions(+), 23 deletions(-)
net/rxrpc/ar-internal.h +1 -0
@@ -451,6 +451,7 @@ enum rxrpc_call_flag {RXRPC_CALL_SEND_PING ,/* A ping will need to be sent */ RXRPC_CALL_PINGING ,/* Ping in process */ RXRPC_CALL_RETRANS_TIMEOUT ,/* Retransmission due to timeout occurred */ + RXRPC_CALL_DISCONNECTED, /* The call has been disconnected */ };/*
net/rxrpc/call_object.c +2 -2
@@ -505,7 +505,7 @@ void rxrpc_release_call(struct rxrpc_soc_debug ("RELEASE CALL %p (%d CONN %p)" , call, call->debug_id, conn); -if (conn) +if (conn && !test_bit (RXRPC_CALL_DISCONNECTED , &call->flags))rxrpc_disconnect_call (call);for (i =0 ; i <RXRPC_RXTX_BUFF_SIZE ; i++) {
@@ -639,6 +639,7 @@ static void rxrpc_rcu_destroy_call(struc { struct rxrpc_call *call = container_of(rcu, struct rxrpc_call, rcu); +rxrpc_put_connection (call->conn);rxrpc_put_peer (call->peer);kfree (call->rxtx_buffer);kfree (call->rxtx_annotations);
@@ -660,7 +661,6 @@ void rxrpc_cleanup_call(struct rxrpc_cal ASSERTCMP(call->state, ==, RXRPC_CALL_COMPLETE);ASSERT (test_bit (RXRPC_CALL_RELEASED , &call->flags)); - ASSERTCMP(call->conn, ==, NULL);/* Clean up the Rx/Tx buffer */ for (i =0 ; i <RXRPC_RXTX_BUFF_SIZE ; i++)
net/rxrpc/conn_client.c +1 -2
@@ -762,9 +762,9 @@ void rxrpc_disconnect_client_call(structstruct rxrpc_net *rxnet =rxrpc_net (sock_net (&call->socket->sk));trace_rxrpc_client (conn, channel, rxrpc_client_chan_disconnect); - call->conn =NULL ;spin_lock (&conn->channel_lock); +set_bit (RXRPC_CALL_DISCONNECTED , &call->flags);/* Calls that have never actually been assigned a channel can simply be * discarded. If the conn didn't get used either, it will follow
@@ -863,7 +863,6 @@ out:spin_unlock (&rxnet->client_conn_cache_lock); out_2:spin_unlock (&conn->channel_lock); -rxrpc_put_connection (conn);_leave ("" );return ;
net/rxrpc/conn_object.c +2 -2
@@ -163,6 +163,8 @@ void __rxrpc_disconnect_call(struct rxrp_enter ("%d,%x" , conn->debug_id, call->cid); +set_bit (RXRPC_CALL_DISCONNECTED , &call->flags); +if (rcu_access_pointer (chan->call) == call) {/* Save the result of the call so that we can repeat it if necessary * through the channel, whilst disposing of the actual call record.
@@ -207,9 +209,7 @@ void rxrpc_disconnect_call(struct rxrpc___rxrpc_disconnect_call (conn, call);spin_unlock (&conn->channel_lock); - call->conn =NULL ; conn->idle_timestamp = jiffies; -rxrpc_put_connection (conn); }/*
net/rxrpc/output.c +9 -17
@@ -96,7 +96,7 @@ static size_t rxrpc_fill_out_ack(struct*/ int rxrpc_send_ack_packet (struct rxrpc_call *call,bool ping) { -struct rxrpc_connection *conn =NULL ; +struct rxrpc_connection *conn;struct rxrpc_ack_buffer *pkt;struct msghdr msg;struct kvec iov[2 ];
@@ -106,18 +106,14 @@ int rxrpc_send_ack_packet(struct rxrpc_cint ret;u8 reason; -spin_lock_bh (&call->lock); -if (call->conn) - conn =rxrpc_get_connection_maybe (call->conn); -spin_unlock_bh (&call->lock); -if (!conn) +if (test_bit (RXRPC_CALL_DISCONNECTED , &call->flags))return -ECONNRESET ; pkt =kzalloc (sizeof (*pkt),GFP_KERNEL ); -if (!pkt) { -rxrpc_put_connection (conn); +if (!pkt)return -ENOMEM ; - } + + conn = call->conn; msg.msg_name = &call->peer->srx.transport; msg.msg_namelen = call->peer->srx.transport_len;
@@ -204,7 +200,6 @@ int rxrpc_send_ack_packet(struct rxrpc_c } out: -rxrpc_put_connection (conn);kfree (pkt);return ret; }
@@ -214,20 +209,18 @@ out:*/ int rxrpc_send_abort_packet (struct rxrpc_call *call) { -struct rxrpc_connection *conn =NULL ; +struct rxrpc_connection *conn;struct rxrpc_abort_buffer pkt;struct msghdr msg;struct kvec iov[1 ];rxrpc_serial_t serial;int ret; -spin_lock_bh (&call->lock); -if (call->conn) - conn =rxrpc_get_connection_maybe (call->conn); -spin_unlock_bh (&call->lock); -if (!conn) +if (test_bit (RXRPC_CALL_DISCONNECTED , &call->flags))return -ECONNRESET ; + conn = call->conn; + msg.msg_name = &call->peer->srx.transport; msg.msg_namelen = call->peer->srx.transport_len; msg.msg_control =NULL ;
@@ -255,7 +248,6 @@ int rxrpc_send_abort_packet(struct rxrpc ret =kernel_sendmsg (conn->params.local->socket, &msg, iov,1 ,sizeof (pkt)); -rxrpc_put_connection (conn);return ret; }
Greg Kroah-Hartman
maintainerPATCH 39/173 ubifs: Reject unsupported ioctl flags explicitly
In reply to Greg Kroah-HartmanFrom: Hou Tao <[email protected]>
commit 2fe8b2d5578d7d142982e3bf62e4c0caf8b8fe02 upstream.
Reject unsupported ioctl flags explicitly, so the following command on a regular ubifs file will fail:
chattr +d ubifs_file
And xfstests generic/424 will pass.
--- fs/ubifs/ioctl.c | 8 ++++++++ 1 file changed, 8 insertions(+)
fs/ubifs/ioctl.c +8 -0
@@ -28,6 +28,11 @@#include <linux/mount.h> #include "ubifs.h" +/* Need to be kept consistent with checked flags in ioctl2ubifs() */ +#define UBIFS_SUPPORTED_IOCTL_FLAGS \ + (FS_COMPR_FL | FS_SYNC_FL | FS_APPEND_FL | \ + FS_IMMUTABLE_FL | FS_DIRSYNC_FL) +/** * ubifs_set_inode_flags - set VFS inode flags. * @inode: VFS inode to set flags for
@@ -166,6 +171,9 @@ long ubifs_ioctl(struct file *file, unsiif (get_user (flags, (int __user *) arg))return -EFAULT ; +if (flags & ~UBIFS_SUPPORTED_IOCTL_FLAGS ) +return -EOPNOTSUPP ; +if (!S_ISDIR (inode->i_mode)) flags &= ~FS_DIRSYNC_FL ;
Greg Kroah-Hartman
maintainerPATCH 32/173 MIPS: fix indentation of the RELOCS message
In reply to Greg Kroah-HartmanFrom: Alexander Lobakin <[email protected]>
commit a53998802e178451701d59d38e36f551422977ba upstream.
quiet_cmd_relocs lacks a whitespace which results in:
LD vmlinux SORTEX vmlinux SYSMAP System.map
RELOCS vmlinux
Building modules, stage 2.
MODPOST 64 modules
After this patch:
LD vmlinux SORTEX vmlinux SYSMAP System.map RELOCS vmlinux
Building modules, stage 2.
MODPOST 64 modules
Typo is present in kernel tree since the introduction of relocatable kernel support in commit e818fac595ab ("MIPS: Generate relocation table when CONFIG_RELOCATABLE"), but the relocation scripts were moved to Makefile.postlink later with commit 44079d3509ae ("MIPS: Use Makefile.postlink to insert relocations into vmlinux").
--- arch/mips/Makefile.postlink | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/mips/Makefile.postlink +1 -1
@@ -12,7 +12,7 @@ __archpost: include scripts/Kbuild.include CMD_RELOCS = arch/mips/boot/tools/relocs -quiet_cmd_relocs = RELOCS $@ +quiet_cmd_relocs = RELOCS $@ cmd_relocs = $(CMD_RELOCS) $@ # `@true` prevents complaint when there is nothing to be done
Greg Kroah-Hartman
maintainerPATCH 34/173 powerpc/xmon: dont access ASDR in VMs
In reply to Greg Kroah-HartmanFrom: Sukadev Bhattiprolu <[email protected]>
commit c2a20711fc181e7f22ee5c16c28cb9578af84729 upstream.
ASDR is HV-privileged and must only be accessed in HV-mode. Fixes a Program Check (0x700) when xmon in a VM dumps SPRs.
--- arch/powerpc/xmon/xmon.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
arch/powerpc/xmon/xmon.c +4 -5
@@ -1830,15 +1830,14 @@ static void dump_300_sprs(void)printf ("pidr = %.16lx tidr = %.16lx\n" ,mfspr (SPRN_PID ),mfspr (SPRN_TIDR )); -printf ("asdr = %.16lx psscr = %.16lx\n" , -mfspr (SPRN_ASDR ), hv ?mfspr (SPRN_PSSCR ) - :mfspr (SPRN_PSSCR_PR )); +printf ("psscr = %.16lx\n" , + hv ?mfspr (SPRN_PSSCR ) :mfspr (SPRN_PSSCR_PR ));if (!hv)return ; -printf ("ptcr = %.16lx\n" , -mfspr (SPRN_PTCR )); +printf ("ptcr = %.16lx asdr = %.16lx\n" , +mfspr (SPRN_PTCR ),mfspr (SPRN_ASDR ));#endif }
Greg Kroah-Hartman
maintainerPATCH 37/173 ACPI: video: Do not export a non working backlight interface on MSI MS-7721 boards
In reply to Greg Kroah-HartmanFrom: Hans de Goede <[email protected]>
commit d21a91629f4b8e794fc4c0e0c17c85cedf1d806c upstream.
Despite our heuristics to not wrongly export a non working ACPI backlight interface on desktop machines, we still end up exporting one on desktops using a motherboard from the MSI MS-7721 series.
I've looked at improving the heuristics, but in this case a quirk seems to be the only way to solve this.
While at it also add a comment to separate the video_detect_force_none entries in the video_detect_dmi_table from other type of entries, as we already do for the other entry types.
--- drivers/acpi/video_detect.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
drivers/acpi/video_detect.c +13 -0
@@ -328,6 +328,11 @@ static const struct dmi_system_id video_ DMI_MATCH(DMI_PRODUCT_NAME, "Precision 7510"), }, }, + +/* +* Desktops which falsely report a backlight and which our heuristics +* for this do not catch. +*/ { .callback = video_detect_force_none, .ident = "Dell OptiPlex 9020M",
@@ -336,6 +341,14 @@ static const struct dmi_system_id video_ DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex 9020M"), }, }, + { + .callback = video_detect_force_none, + .ident = "MSI MS-7721", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "MSI"), + DMI_MATCH(DMI_PRODUCT_NAME, "MS-7721"), + }, + }, { }, };
Greg Kroah-Hartman
maintainerPATCH 60/173 ftrace: Add comment to why rcu_dereference_sched() is open coded
In reply to Greg Kroah-HartmanFrom: Steven Rostedt (VMware) <[email protected]>
[ Upstream commit 16052dd5bdfa16dbe18d8c1d4cde2ddab9d23177 ]
Because the function graph tracer can execute in sections where RCU is not "watching", the rcu_dereference_sched() for the has needs to be open coded. This is fine because the RCU "flavor" of the ftrace hash is protected by its own RCU handling (it does its own little synchronization on every CPU and does not rely on RCU sched).
--- kernel/trace/trace.h | 10 ++++++++++ 1 file changed, 10 insertions(+)
kernel/trace/trace.h +10 -0
@@ -879,6 +879,11 @@ static inline int ftrace_graph_addr(struct ftrace_graph_ent *trace)preempt_disable_notrace (); +/* +* Have to open code "rcu_dereference_sched()" because the +* function graph tracer can be called when RCU is not +* "watching". +*/ hash =rcu_dereference_protected (ftrace_graph_hash, !preemptible ());if (ftrace_hash_empty (hash)) {
@@ -926,6 +931,11 @@ static inline int ftrace_graph_notrace_addr(unsigned long addr)preempt_disable_notrace (); +/* +* Have to open code "rcu_dereference_sched()" because the +* function graph tracer can be called when RCU is not +* "watching". +*/ notrace_hash =rcu_dereference_protected (ftrace_graph_notrace_hash, !preemptible ());
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 63/173 crypto: ccp - set max RSA modulus size for v3 platform devices as well
In reply to Greg Kroah-HartmanFrom: Ard Biesheuvel <[email protected]>
commit 11548f5a5747813ff84bed6f2ea01100053b0d8d upstream.
AMD Seattle incorporates a non-PCI version of the v3 CCP crypto accelerator, and this version was left behind when the maximum RSA modulus size was parameterized in order to support v5 hardware which supports larger moduli than v3 hardware does. Due to this oversight, RSA acceleration no longer works at all on these systems.
Fix this by setting the .rsamax property to the appropriate value for v3 platform hardware.
--- drivers/crypto/ccp/ccp-dev-v3.c | 1 + 1 file changed, 1 insertion(+)
drivers/crypto/ccp/ccp-dev-v3.c +1 -0
@@ -590,6 +590,7 @@ const struct ccp_vdata ccpv3_platform = .setup = NULL, .perform = &ccp3_actions, .offset = 0, + .rsamax = CCP_RSA_MAX_WIDTH, };const struct ccp_vdata ccpv3 = {
Greg Kroah-Hartman
maintainerPATCH 64/173 crypto: pcrypt - Do not clear MAY_SLEEP flag in original request
In reply to Greg Kroah-HartmanFrom: Herbert Xu <[email protected]>
commit e8d998264bffade3cfe0536559f712ab9058d654 upstream.
We should not be modifying the original request's MAY_SLEEP flag upon completion. It makes no sense to do so anyway.
--- crypto/pcrypt.c | 1 - 1 file changed, 1 deletion(-)
crypto/pcrypt.c +0 -1
@@ -130,7 +130,6 @@ static void pcrypt_aead_done(struct crypstruct padata_priv *padata =pcrypt_request_padata (preq); padata->info = err; - req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP ;padata_do_serial (padata); }
Greg Kroah-Hartman
maintainerPATCH 66/173 crypto: api - Fix race condition in crypto_spawn_alg
In reply to Greg Kroah-HartmanFrom: Herbert Xu <[email protected]>
commit 73669cc556462f4e50376538d77ee312142e8a8a upstream.
The function crypto_spawn_alg is racy because it drops the lock before shooting the dying algorithm. The algorithm could disappear altogether before we shoot it.
This patch fixes it by moving the shooting into the locked section.
--- crypto/algapi.c | 16 +++++----------- crypto/api.c | 3 +-- crypto/internal.h | 1 - 3 files changed, 6 insertions(+), 14 deletions(-)
crypto/algapi.c +5 -11
@@ -662,22 +662,16 @@ EXPORT_SYMBOL_GPL(crypto_drop_spawn);static struct crypto_alg *crypto_spawn_alg (struct crypto_spawn *spawn) {struct crypto_alg *alg; -struct crypto_alg *alg2;down_read (&crypto_alg_sem); alg = spawn->alg; - alg2 = alg; -if (alg2) - alg2 =crypto_mod_get (alg2); -up_read (&crypto_alg_sem); - -if (!alg2) { -if (alg) -crypto_shoot_alg (alg); -return ERR_PTR (-EAGAIN ); +if (alg && !crypto_mod_get (alg)) { + alg->cra_flags |=CRYPTO_ALG_DYING ; + alg =NULL ; } +up_read (&crypto_alg_sem); -return alg; +return alg ?:ERR_PTR (-EAGAIN ); } struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
crypto/api.c +1 -2
@@ -339,13 +339,12 @@ static unsigned int crypto_ctxsize(strucreturn len; } -void crypto_shoot_alg (struct crypto_alg *alg) +static void crypto_shoot_alg (struct crypto_alg *alg) {down_write (&crypto_alg_sem); alg->cra_flags |=CRYPTO_ALG_DYING ;up_write (&crypto_alg_sem); } -EXPORT_SYMBOL_GPL (crypto_shoot_alg);struct crypto_tfm *__crypto_alloc_tfm (struct crypto_alg *alg,u32 type,u32 mask)
crypto/internal.h +0 -1
@@ -84,7 +84,6 @@ void crypto_alg_tested(const char *name,void crypto_remove_spawns (struct crypto_alg *alg,struct list_head *list,struct crypto_alg *nalg);void crypto_remove_final (struct list_head *list); -void crypto_shoot_alg (struct crypto_alg *alg);struct crypto_tfm *__crypto_alloc_tfm (struct crypto_alg *alg,u32 type,u32 mask); void *crypto_create_tfm(struct crypto_alg *alg,
Greg Kroah-Hartman
maintainerPATCH 51/173 f2fs: code cleanup for f2fs_statfs_project()
In reply to Greg Kroah-HartmanFrom: Chengguang Xu <[email protected]>
commit bf2cbd3c57159c2b639ee8797b52ab5af180bf83 upstream.
Calling min_not_zero() to simplify complicated prjquota limit comparison in f2fs_statfs_project().
--- fs/f2fs/super.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-)
fs/f2fs/super.c +4 -12
@@ -912,12 +912,8 @@ static int f2fs_statfs_project(struct sureturn PTR_ERR (dquot);spin_lock (&dq_data_lock); - limit =0 ; -if (dquot->dq_dqb.dqb_bsoftlimit) - limit = dquot->dq_dqb.dqb_bsoftlimit; -if (dquot->dq_dqb.dqb_bhardlimit && - (!limit || dquot->dq_dqb.dqb_bhardlimit < limit)) - limit = dquot->dq_dqb.dqb_bhardlimit; + limit =min_not_zero (dquot->dq_dqb.dqb_bsoftlimit, + dquot->dq_dqb.dqb_bhardlimit);if (limit) limit >>= sb->s_blocksize_bits;
@@ -929,12 +925,8 @@ static int f2fs_statfs_project(struct su (buf->f_blocks - curblock) : 0; } - limit =0 ; -if (dquot->dq_dqb.dqb_isoftlimit) - limit = dquot->dq_dqb.dqb_isoftlimit; -if (dquot->dq_dqb.dqb_ihardlimit && - (!limit || dquot->dq_dqb.dqb_ihardlimit < limit)) - limit = dquot->dq_dqb.dqb_ihardlimit; + limit =min_not_zero (dquot->dq_dqb.dqb_isoftlimit, + dquot->dq_dqb.dqb_ihardlimit);if (limit && buf->f_files > limit) { buf->f_files = limit;
Greg Kroah-Hartman
maintainerPATCH 57/173 padata: Remove broken queue flushing
In reply to Greg Kroah-HartmanFrom: Herbert Xu <[email protected]>
[ Upstream commit 07928d9bfc81640bab36f5190e8725894d93b659 ]
The function padata_flush_queues is fundamentally broken because it cannot force padata users to complete the request that is underway. IOW padata has to passively wait for the completion of any outstanding work.
As it stands flushing is used in two places. Its use in padata_stop is simply unnecessary because nothing depends on the queues to be flushed afterwards.
The other use in padata_replace is more substantial as we depend on it to free the old pd structure. This patch instead uses the pd->refcnt to dynamically free the pd structure once all requests are complete.
--- kernel/padata.c | 46 ++++++++++++---------------------------------- 1 file changed, 12 insertions(+), 34 deletions(-)
kernel/padata.c +12 -34
@@ -34,6 +34,8 @@#define MAX_OBJ_NUM 1000 +static void padata_free_pd (struct parallel_data *pd); +static int padata_index_to_cpu (struct parallel_data *pd,int cpu_index) {int cpu, target_cpu;
@@ -292,6 +294,7 @@ static void padata_serial_worker(struct work_struct *serial_work)struct padata_serial_queue *squeue;struct parallel_data *pd;LIST_HEAD (local_list); +int cnt;local_bh_disable (); squeue = container_of(serial_work, struct padata_serial_queue, work);
@@ -301,6 +304,8 @@ static void padata_serial_worker(struct work_struct *serial_work)list_replace_init (&squeue->serial.list, &local_list);spin_unlock (&squeue->serial.lock); + cnt =0 ; +while (!list_empty (&local_list)) {struct padata_priv *padata;
@@ -310,9 +315,12 @@ static void padata_serial_worker(struct work_struct *serial_work)list_del_init (&padata->list); padata->serial (padata); -atomic_dec (&pd->refcnt); + cnt++; }local_bh_enable (); + +if (atomic_sub_and_test (cnt, &pd->refcnt)) +padata_free_pd (pd); }/**
@@ -435,8 +443,7 @@ static struct parallel_data *padata_alloc_pd(struct padata_instance *pinst,setup_timer (&pd->timer, padata_reorder_timer, (unsigned long )pd);atomic_set (&pd->seq_nr,-1 );atomic_set (&pd->reorder_objects,0 ); -atomic_set (&pd->refcnt,0 ); - pd->pinst = pinst; +atomic_set (&pd->refcnt,1 );spin_lock_init (&pd->lock);return pd;
@@ -460,31 +467,6 @@ static void padata_free_pd(struct parallel_data *pd)kfree (pd); } -/* Flush all objects out of the padata queues. */ -static void padata_flush_queues (struct parallel_data *pd) -{ -int cpu; -struct padata_parallel_queue *pqueue; -struct padata_serial_queue *squeue; - -for_each_cpu (cpu, pd->cpumask.pcpu) { - pqueue =per_cpu_ptr (pd->pqueue, cpu); -flush_work (&pqueue->work); - } - -del_timer_sync (&pd->timer); - -if (atomic_read (&pd->reorder_objects)) -padata_reorder (pd); - -for_each_cpu (cpu, pd->cpumask.cbcpu) { - squeue =per_cpu_ptr (pd->squeue, cpu); -flush_work (&squeue->work); - } - -BUG_ON (atomic_read (&pd->refcnt) !=0 ); -} -static void __padata_start (struct padata_instance *pinst) { pinst->flags |=PADATA_INIT ;
@@ -498,10 +480,6 @@ static void __padata_stop(struct padata_instance *pinst) pinst->flags &= ~PADATA_INIT ;synchronize_rcu (); - -get_online_cpus (); -padata_flush_queues (pinst->pd); -put_online_cpus (); }/* Replace the internal control structure with a new one. */
@@ -522,8 +500,8 @@ static void padata_replace(struct padata_instance *pinst,if (!cpumask_equal (pd_old->cpumask.cbcpu, pd_new->cpumask.cbcpu)) notification_mask |=PADATA_CPU_SERIAL ; -padata_flush_queues (pd_old); -padata_free_pd (pd_old); +if (atomic_dec_and_test (&pd_old->refcnt)) +padata_free_pd (pd_old);if (notification_mask) blocking_notifier_call_chain(&pinst->cpumask_change_notifier,
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 80/173 KVM: x86: Protect DR-based index computations from Spectre-v1/L1TF attacks
In reply to Greg Kroah-HartmanFrom: Marios Pomonis <[email protected]>
commit ea740059ecb37807ba47b84b33d1447435a8d868 upstream.
This fixes a Spectre-v1/L1TF vulnerability in __kvm_set_dr() and kvm_get_dr().
Both kvm_get_dr() and kvm_set_dr() (a wrapper of __kvm_set_dr()) are exported symbols so KVM should tream them conservatively from a security perspective.
--- arch/x86/kvm/x86.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
arch/x86/kvm/x86.c +6 -2
@@ -924,9 +924,11 @@ static u64 kvm_dr6_fixed(struct kvm_vcpustatic int __kvm_set_dr (struct kvm_vcpu *vcpu,int dr,unsigned long val) { +size_t size =ARRAY_SIZE (vcpu->arch.db); +switch (dr) { case 0 ... 3: - vcpu->arch.db[dr] = val; + vcpu->arch.db[array_index_nospec (dr, size)] = val;if (!(vcpu->guest_debug &KVM_GUESTDBG_USE_HW_BP )) vcpu->arch.eff_db[dr] = val;break ;
@@ -963,9 +965,11 @@ EXPORT_SYMBOL_GPL(kvm_set_dr);int kvm_get_dr (struct kvm_vcpu *vcpu,int dr,unsigned long *val) { +size_t size =ARRAY_SIZE (vcpu->arch.db); +switch (dr) { case 0 ... 3: - *val = vcpu->arch.db[dr]; + *val = vcpu->arch.db[array_index_nospec (dr, size)];break ;case 4 :/* fall through */
Greg Kroah-Hartman
maintainerPATCH 86/173 KVM: x86: Protect MSR-based index computations from Spectre-v1/L1TF attacks in x86.c
In reply to Greg Kroah-HartmanFrom: Marios Pomonis <[email protected]>
commit 6ec4c5eee1750d5d17951c4e1960d953376a0dda upstream.
This fixes a Spectre-v1/L1TF vulnerability in set_msr_mce() and get_msr_mce().
Both functions contain index computations based on the (attacker-controlled) MSR number.
--- arch/x86/kvm/x86.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
arch/x86/kvm/x86.c +8 -2
@@ -2165,7 +2165,10 @@ static int set_msr_mce(struct kvm_vcpu *default :if (msr >=MSR_IA32_MC0_CTL && msr <MSR_IA32_MCx_CTL (bank_num)) { -u32 offset = msr -MSR_IA32_MC0_CTL ; +u32 offset =array_index_nospec ( + msr -MSR_IA32_MC0_CTL , +MSR_IA32_MCx_CTL (bank_num) -MSR_IA32_MC0_CTL ); +/* only 0 or all 1s can be written to IA32_MCi_CTL * some Linux kernels though clear bit 10 in bank 4 to * workaround a BIOS/GART TBL issue on AMD K8s, ignore
@@ -2549,7 +2552,10 @@ static int get_msr_mce(struct kvm_vcpu *default :if (msr >=MSR_IA32_MC0_CTL && msr <MSR_IA32_MCx_CTL (bank_num)) { -u32 offset = msr -MSR_IA32_MC0_CTL ; +u32 offset =array_index_nospec ( + msr -MSR_IA32_MC0_CTL , +MSR_IA32_MCx_CTL (bank_num) -MSR_IA32_MC0_CTL ); + data = vcpu->arch.mce_banks[offset];break ; }
Greg Kroah-Hartman
maintainerPATCH 75/173 sunrpc: expiry_time should be seconds not timeval
In reply to Greg Kroah-HartmanFrom: Roberto Bergantinos Corpas <[email protected]>
commit 3d96208c30f84d6edf9ab4fac813306ac0d20c10 upstream.
When upcalling gssproxy, cache_head.expiry_time is set as a timeval, not seconds since boot. As such, RPC cache expiry logic will not clean expired objects created under auth.rpcsec.context cache.
This has proven to cause kernel memory leaks on field. Using 64 bit variants of getboottime/timespec
Expiration times have worked this way since 2010's c5b29f885afe "sunrpc:
use seconds since boot in expiry cache". The gssproxy code introduced in 2012 added gss_proxy_save_rsc and introduced the bug. That's a while for this to lurk, but it required a bit of an extreme case to make it obvious.
--- net/sunrpc/auth_gss/svcauth_gss.c | 4 ++++ 1 file changed, 4 insertions(+)
net/sunrpc/auth_gss/svcauth_gss.c +4 -0
@@ -1188,6 +1188,7 @@ static int gss_proxy_save_rsc(struct cacdprintk ("RPC: No creds found!\n" ); goto out; }else { +struct timespec64 boot;/* steal creds */ rsci.cred = ud->creds;
@@ -1208,6 +1209,9 @@ static int gss_proxy_save_rsc(struct cac &expiry, GFP_KERNEL);if (status) goto out; + +getboottime64 (&boot); + expiry -= boot.tv_sec; } rsci.h.expiry_time = expiry;
Greg Kroah-Hartman
maintainerPATCH 100/173 NFC: pn544: Adjust indentation in pn544_hci_check_presence
In reply to Greg Kroah-HartmanFrom: Nathan Chancellor <[email protected]>
commit 5080832627b65e3772a35d1dced68c64e2b24442 upstream.
Clang warns
../drivers/nfc/pn544/pn544.c:696:4: warning: misleading indentation; statement is not part of the previous 'if' [-Wmisleading-indentation]
return nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE, ^../drivers/nfc/pn544/pn544.c:692:3: note: previous statement is here
if (target->nfcid1_len != 4 && target->nfcid1_len != 7 &&
^1 warning generated.
This warning occurs because there is a space after the tab on this line. Remove it so that the indentation is consistent with the Linux kernel coding style and clang no longer warns.
--- drivers/nfc/pn544/pn544.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/nfc/pn544/pn544.c +1 -1
@@ -704,7 +704,7 @@ static int pn544_hci_check_presence(stru target->nfcid1_len != 10)return -EOPNOTSUPP ; -return nfc_hci_send_cmd (hdev,NFC_HCI_RF_READER_A_GATE , +return nfc_hci_send_cmd (hdev,NFC_HCI_RF_READER_A_GATE ,PN544_RF_READER_CMD_ACTIVATE_NEXT , target->nfcid1, target->nfcid1_len,NULL ); } else if (target->supported_protocols & (NFC_PROTO_JEWEL_MASK |
Greg Kroah-Hartman
maintainerPATCH 103/173 net: tulip: Adjust indentation in {dmfe, uli526x}_init_module
In reply to Greg Kroah-HartmanFrom: Nathan Chancellor <[email protected]>
commit fe06bf3d83ef0d92f35a24e03297172e92ce9ce3 upstream.
Clang warns:
../drivers/net/ethernet/dec/tulip/uli526x.c:1812:3: warning: misleading indentation; statement is not part of the previous 'if' [-Wmisleading-indentation]
switch (mode) {
^
../drivers/net/ethernet/dec/tulip/uli526x.c:1809:2: note: previous
statement is here
if (cr6set)
^1 warning generated.
../drivers/net/ethernet/dec/tulip/dmfe.c:2217:3: warning: misleading indentation; statement is not part of the previous 'if' [-Wmisleading-indentation]
switch(mode) {
^
../drivers/net/ethernet/dec/tulip/dmfe.c:2214:2: note: previous
statement is here
if (cr6set)
^1 warning generated.
This warning occurs because there is a space before the tab on these lines. Remove them so that the indentation is consistent with the Linux kernel coding style and clang no longer warns.
While we are here, adjust the default block in dmfe_init_module to have a proper break between the label and assignment and add a space between the switch and opening parentheses to avoid a checkpatch warning.
--- drivers/net/ethernet/dec/tulip/dmfe.c | 7 ++++--- drivers/net/ethernet/dec/tulip/uli526x.c | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-)
drivers/net/ethernet/dec/tulip/dmfe.c +4 -3
@@ -2224,15 +2224,16 @@ static int __init dmfe_init_module(void)if (cr6set) dmfe_cr6_user_set = cr6set; -switch (mode) { -case DMFE_10MHF : +switch (mode) { +case DMFE_10MHF :case DMFE_100MHF :case DMFE_10MFD :case DMFE_100MFD :case DMFE_1M_HPNA : dmfe_media_mode = mode;break ; -default :dmfe_media_mode =DMFE_AUTO ; +default : + dmfe_media_mode =DMFE_AUTO ;break ; }
drivers/net/ethernet/dec/tulip/uli526x.c +2 -2
@@ -1819,8 +1819,8 @@ static int __init uli526x_init_module(voif (cr6set) uli526x_cr6_user_set = cr6set; -switch (mode) { -case ULI526X_10MHF : +switch (mode) { +case ULI526X_10MHF :case ULI526X_100MHF :case ULI526X_10MFD :case ULI526X_100MFD :
Greg Kroah-Hartman
maintainerPATCH 90/173 KVM: PPC: Book3S PR: Free shared page if mmu initialization fails
In reply to Greg Kroah-HartmanFrom: Sean Christopherson <[email protected]>
commit cb10bf9194f4d2c5d830eddca861f7ca0fecdbb4 upstream.
Explicitly free the shared page if kvmppc_mmu_init() fails during kvmppc_core_vcpu_create(), as the page is freed only in kvmppc_core_vcpu_free(), which is not reached via kvm_vcpu_uninit().
--- arch/powerpc/kvm/book3s_pr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
arch/powerpc/kvm/book3s_pr.c +3 -1
@@ -1482,10 +1482,12 @@ static struct kvm_vcpu *kvmppc_core_vcpu err =kvmppc_mmu_init (vcpu);if (err <0 ) - goto uninit_vcpu; + goto free_shared_page;return vcpu; +free_shared_page: +free_page ((unsigned long )vcpu->arch.shared); uninit_vcpu:kvm_vcpu_uninit (vcpu); free_shadow_vcpu:
Greg Kroah-Hartman
maintainerPATCH 93/173 scsi: qla2xxx: Fix the endianness of the qla82xx_get_fw_size() return type
In reply to Greg Kroah-HartmanFrom: Bart Van Assche <[email protected]>
commit 3f5f7335e5e234e340b48ecb24c2aba98a61f934 upstream.
Since qla82xx_get_fw_size() returns a number in CPU-endian format, change its return type from __le32 into u32. This patch does not change any functionality.
--- drivers/scsi/qla2xxx/qla_nx.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/scsi/qla2xxx/qla_nx.c +3 -4
@@ -1605,8 +1605,7 @@ qla82xx_get_bootld_offset(struct qla_hw_return (u8 *)&ha->hablob->fw->data[offset]; } -static __le32 -qla82xx_get_fw_size (struct qla_hw_data *ha) +static u32 qla82xx_get_fw_size (struct qla_hw_data *ha) {struct qla82xx_uri_data_desc *uri_desc =NULL ;
@@ -1617,7 +1616,7 @@ qla82xx_get_fw_size(struct qla_hw_data *return cpu_to_le32 (uri_desc->size); } -return cpu_to_le32 (*(u32 *)&ha->hablob->fw->data[FW_SIZE_OFFSET ]); +return get_unaligned_le32 (&ha->hablob->fw->data[FW_SIZE_OFFSET ]); } static u8 *
@@ -1808,7 +1807,7 @@ qla82xx_fw_load_from_blob(struct qla_hw_ } flashaddr =FLASH_ADDR_START ; - size = (__force u32 )qla82xx_get_fw_size (ha) /8 ; + size =qla82xx_get_fw_size (ha) /8 ; ptr64 = (u64 *)qla82xx_get_fw_offs (ha);for (i =0 ; i < size; i++) {
Greg Kroah-Hartman
maintainerPATCH 97/173 phy: qualcomm: Adjust indentation in read_poll_timeout
In reply to Greg Kroah-HartmanFrom: Nathan Chancellor <[email protected]>
commit a89806c998ee123bb9c0f18526e55afd12c0c0ab upstream.
Clang warns:
../drivers/phy/qualcomm/phy-qcom-apq8064-sata.c:83:4: warning:
misleading indentation; statement is not part of the previous 'if' [-Wmisleading-indentation]
usleep_range(DELAY_INTERVAL_US, DELAY_INTERVAL_US + 50);
^../drivers/phy/qualcomm/phy-qcom-apq8064-sata.c:80:3: note: previous statement is here
if (readl_relaxed(addr) & mask)
^
1 warning generated.
This warning occurs because there is a space after the tab on this line. Remove it so that the indentation is consistent with the Linux kernel coding style and clang no longer warns.
--- drivers/phy/qualcomm/phy-qcom-apq8064-sata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/phy/qualcomm/phy-qcom-apq8064-sata.c +1 -1
@@ -88,7 +88,7 @@ static int read_poll_timeout(void __iomeif (readl_relaxed (addr) & mask)return 0 ; -usleep_range (DELAY_INTERVAL_US ,DELAY_INTERVAL_US +50 ); +usleep_range (DELAY_INTERVAL_US ,DELAY_INTERVAL_US +50 ); }while (!time_after (jiffies, timeout));return (readl_relaxed (addr) & mask) ?0 : -ETIMEDOUT ;
Greg Kroah-Hartman
maintainerPATCH 108/173 ubi: fastmap: Fix inverted logic in seen selfcheck
In reply to Greg Kroah-HartmanFrom: Sascha Hauer <[email protected]>
commit ef5aafb6e4e9942a28cd300bdcda21ce6cbaf045 upstream.
set_seen() sets the bit corresponding to the PEB number in the bitmap, so when self_check_seen() wants to find PEBs that haven't been seen we have to print the PEBs that have their bit cleared, not the ones which have it set.
--- drivers/mtd/ubi/fastmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mtd/ubi/fastmap.c +1 -1
@@ -73,7 +73,7 @@ static int self_check_seen(struct ubi_dereturn 0 ;for (pnum =0 ; pnum < ubi->peb_count; pnum++) { -if (test_bit (pnum, seen) && ubi->lookuptbl[pnum]) { +if (!test_bit (pnum, seen) && ubi->lookuptbl[pnum]) {ubi_err (ubi,"self-check failed for PEB %d, fastmap didn't see it" , pnum); ret = -EINVAL ; }
Greg Kroah-Hartman
maintainerPATCH 125/173 Btrfs: fix race between adding and putting tree mod seq elements and nodes
In reply to Greg Kroah-HartmanFrom: Filipe Manana <[email protected]>
[ Upstream commit 7227ff4de55d931bbdc156c8ef0ce4f100c78a5b ]
There is a race between adding and removing elements to the tree mod log list and rbtree that can lead to use-after-free problems.
Consider the following example that explains how/why the problems happens:
1) Task A has mod log element with sequence number 200. It currently is the only element in the mod log list;
2) Task A calls btrfs_put_tree_mod_seq() because it no longer needs to access the tree mod log. When it enters the function, it initializes 'min_seq' to (u64)-1. Then it acquires the lock 'tree_mod_seq_lock' before checking if there are other elements in the mod seq list. Since the list it empty, 'min_seq' remains set to (u64)-1. Then it unlocks the lock 'tree_mod_seq_lock';
3) Before task A acquires the lock 'tree_mod_log_lock', task B adds itself to the mod seq list through btrfs_get_tree_mod_seq() and gets a sequence number of 201;
4) Some other task, name it task C, modifies a btree and because there elements in the mod seq list, it adds a tree mod elem to the tree mod log rbtree. That node added to the mod log rbtree is assigned a sequence number of 202;
5) Task B, which is doing fiemap and resolving indirect back references, calls btrfs get_old_root(), with 'time_seq' == 201, which in turn calls tree_mod_log_search() - the search returns the mod log node from the rbtree with sequence number 202, created by task C;
6) Task A now acquires the lock 'tree_mod_log_lock', starts iterating the mod log rbtree and finds the node with sequence number 202. Since 202 is less than the previously computed 'min_seq', (u64)-1, it removes the node and frees it;
7) Task B still has a pointer to the node with sequence number 202, and it dereferences the pointer itself and through the call to __tree_mod_log_rewind(), resulting in a use-after-free problem.
This issue can be triggered sporadically with the test case generic/561 from fstests, and it happens more frequently with a higher number of duperemove processes. When it happens to me, it either freezes the VM or it produces a trace like the following before crashing:
[ 1245.321140] general protection fault: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC PTI [ 1245.321200] CPU: 1 PID: 26997 Comm: pool Not tainted 5.5.0-rc6-btrfs-next-52 #1 [ 1245.321235] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-0-ga698c8995f-prebuilt.qemu.org 04/01/2014 [ 1245.321287] RIP: 0010:rb_next+0x16/0x50 [ 1245.321307] Code: .... [ 1245.321372] RSP: 0018:ffffa151c4d039b0 EFLAGS: 00010202 [ 1245.321388] RAX: 6b6b6b6b6b6b6b6b RBX: ffff8ae221363c80 RCX: 6b6b6b6b6b6b6b6b [ 1245.321409] RDX: 0000000000000001 RSI: 0000000000000000 RDI: ffff8ae221363c80 [ 1245.321439] RBP: ffff8ae20fcc4688 R08: 0000000000000002 R09: 0000000000000000 [ 1245.321475] R10: ffff8ae20b120910 R11: 00000000243f8bb1 R12: 0000000000000038 [ 1245.321506] R13: ffff8ae221363c80 R14: 000000000000075f R15: ffff8ae223f762b8 [ 1245.321539] FS: 00007fdee1ec7700(0000) GS:ffff8ae236c80000(0000) knlGS:0000000000000000 [ 1245.321591] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 1245.321614] CR2: 00007fded4030c48 CR3: 000000021da16003 CR4: 00000000003606e0 [ 1245.321642] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 1245.321668] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 1245.321706] Call Trace: [ 1245.321798] __tree_mod_log_rewind+0xbf/0x280 [btrfs] [ 1245.321841] btrfs_search_old_slot+0x105/0xd00 [btrfs] [ 1245.321877] resolve_indirect_refs+0x1eb/0xc60 [btrfs] [ 1245.321912] find_parent_nodes+0x3dc/0x11b0 [btrfs] [ 1245.321947] btrfs_check_shared+0x115/0x1c0 [btrfs] [ 1245.321980] ? extent_fiemap+0x59d/0x6d0 [btrfs] [ 1245.322029] extent_fiemap+0x59d/0x6d0 [btrfs] [ 1245.322066] do_vfs_ioctl+0x45a/0x750 [ 1245.322081] ksys_ioctl+0x70/0x80 [ 1245.322092] ? trace_hardirqs_off_thunk+0x1a/0x1c [ 1245.322113] __x64_sys_ioctl+0x16/0x20 [ 1245.322126] do_syscall_64+0x5c/0x280 [ 1245.322139] entry_SYSCALL_64_after_hwframe+0x49/0xbe [ 1245.322155] RIP: 0033:0x7fdee3942dd7 [ 1245.322177] Code: .... [ 1245.322258] RSP: 002b:00007fdee1ec6c88 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 [ 1245.322294] RAX: ffffffffffffffda RBX: 00007fded40210d8 RCX: 00007fdee3942dd7 [ 1245.322314] RDX: 00007fded40210d8 RSI: 00000000c020660b RDI: 0000000000000004 [ 1245.322337] RBP: 0000562aa89e7510 R08: 0000000000000000 R09: 00007fdee1ec6d44 [ 1245.322369] R10: 0000000000000073 R11: 0000000000000246 R12: 00007fdee1ec6d48 [ 1245.322390] R13: 00007fdee1ec6d40 R14: 00007fded40210d0 R15: 00007fdee1ec6d50 [ 1245.322423] Modules linked in: .... [ 1245.323443] ---[ end trace 01de1e9ec5dff3cd ]---
Fix this by ensuring that btrfs_put_tree_mod_seq() computes the minimum sequence number and iterates the rbtree while holding the lock 'tree_mod_log_lock' in write mode. Also get rid of the 'tree_mod_seq_lock' lock, since it is now redundant.
--- fs/btrfs/ctree.c | 8 ++------ fs/btrfs/ctree.h | 6 ++---- fs/btrfs/delayed-ref.c | 8 ++++---- fs/btrfs/disk-io.c | 1 - fs/btrfs/tests/btrfs-tests.c | 1 - 5 files changed, 8 insertions(+), 16 deletions(-)
fs/btrfs/ctree.c +2 -6
@@ -354,12 +354,10 @@ u64 btrfs_get_tree_mod_seq(struct btrfs_fs_info *fs_info, struct seq_list *elem) {write_lock (&fs_info->tree_mod_log_lock); -spin_lock (&fs_info->tree_mod_seq_lock);if (!elem->seq) { elem->seq =btrfs_inc_tree_mod_seq (fs_info);list_add_tail (&elem->list, &fs_info->tree_mod_seq_list); } -spin_unlock (&fs_info->tree_mod_seq_lock);write_unlock (&fs_info->tree_mod_log_lock);return elem->seq;
@@ -379,7 +377,7 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info,if (!seq_putting)return ; -spin_lock (&fs_info->tree_mod_seq_lock); +write_lock (&fs_info->tree_mod_log_lock);list_del (&elem->list); elem->seq =0 ;
@@ -390,19 +388,17 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info,* blocker with lower sequence number exists, we * cannot remove anything from the log */ -spin_unlock (&fs_info->tree_mod_seq_lock); +write_unlock (&fs_info->tree_mod_log_lock);return ; } min_seq = cur_elem->seq; } } -spin_unlock (&fs_info->tree_mod_seq_lock);/* * anything that's lower than the lowest existing (read: blocked) * sequence number can be removed from the tree. */ -write_lock (&fs_info->tree_mod_log_lock); tm_root = &fs_info->tree_mod_log;for (node =rb_first (tm_root); node; node = next) { next =rb_next (node);
fs/btrfs/ctree.h +2 -4
@@ -869,14 +869,12 @@ struct btrfs_fs_info {struct list_head delayed_iputs;struct mutex cleaner_delayed_iput_mutex; -/* this protects tree_mod_seq_list */ -spinlock_t tree_mod_seq_lock;atomic64_t tree_mod_seq; -struct list_head tree_mod_seq_list; -/* this protects tree_mod_log */ +/* this protects tree_mod_log and tree_mod_seq_list */ rwlock_t tree_mod_log_lock;struct rb_root tree_mod_log; +struct list_head tree_mod_seq_list;atomic_t nr_async_submits;atomic_t async_submit_draining;
fs/btrfs/delayed-ref.c +4 -4
@@ -281,7 +281,7 @@ void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans,if (head->is_data)return ; -spin_lock (&fs_info->tree_mod_seq_lock); +read_lock (&fs_info->tree_mod_log_lock);if (!list_empty (&fs_info->tree_mod_seq_list)) {struct seq_list *elem;
@@ -289,7 +289,7 @@ void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans, struct seq_list, list); seq = elem->seq; } -spin_unlock (&fs_info->tree_mod_seq_lock); +read_unlock (&fs_info->tree_mod_log_lock); ref = list_first_entry(&head->ref_list, struct btrfs_delayed_ref_node, list);
@@ -317,7 +317,7 @@ int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info,struct seq_list *elem;int ret =0 ; -spin_lock (&fs_info->tree_mod_seq_lock); +read_lock (&fs_info->tree_mod_log_lock);if (!list_empty (&fs_info->tree_mod_seq_list)) { elem =list_first_entry (&fs_info->tree_mod_seq_list, struct seq_list, list);
@@ -331,7 +331,7 @@ int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info, } } -spin_unlock (&fs_info->tree_mod_seq_lock); +read_unlock (&fs_info->tree_mod_log_lock);return ret; }
fs/btrfs/disk-io.c +0 -1
@@ -2455,7 +2455,6 @@ int open_ctree(struct super_block *sb,spin_lock_init (&fs_info->fs_roots_radix_lock);spin_lock_init (&fs_info->delayed_iput_lock);spin_lock_init (&fs_info->defrag_inodes_lock); -spin_lock_init (&fs_info->tree_mod_seq_lock);spin_lock_init (&fs_info->super_lock);spin_lock_init (&fs_info->qgroup_op_lock);spin_lock_init (&fs_info->buffer_lock);
fs/btrfs/tests/btrfs-tests.c +0 -1
@@ -115,7 +115,6 @@ struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(u32 nodesize, u32 sectorsize)spin_lock_init (&fs_info->qgroup_op_lock);spin_lock_init (&fs_info->super_lock);spin_lock_init (&fs_info->fs_roots_radix_lock); -spin_lock_init (&fs_info->tree_mod_seq_lock);mutex_init (&fs_info->qgroup_ioctl_lock);mutex_init (&fs_info->qgroup_rescan_lock);rwlock_init (&fs_info->tree_mod_log_lock);
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 109/173 ubi: Fix an error pointer dereference in error handling code
In reply to Greg Kroah-HartmanFrom: Dan Carpenter <[email protected]>
commit 5d3805af279c93ef49a64701f35254676d709622 upstream.
If "seen_pebs = init_seen(ubi);" fails then "seen_pebs" is an error pointer and we try to kfree() it which results in an Oops.
This patch re-arranges the error handling so now it only frees things which have been allocated successfully.
--- drivers/mtd/ubi/fastmap.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-)
drivers/mtd/ubi/fastmap.c +12 -9
@@ -1147,7 +1147,7 @@ static int ubi_write_fastmap(struct ubi_struct rb_node *tmp_rb;int ret, i, j, free_peb_count, used_peb_count, vol_count;int scrub_peb_count, erase_peb_count; -unsigned long *seen_pebs =NULL ; +unsigned long *seen_pebs; fm_raw = ubi->fm_buf;memset (ubi->fm_buf,0 , ubi->fm_size);
@@ -1161,7 +1161,7 @@ static int ubi_write_fastmap(struct ubi_ dvbuf =new_fm_vbuf (ubi,UBI_FM_DATA_VOLUME_ID );if (!dvbuf) { ret = -ENOMEM ; - goto out_kfree; + goto out_free_avbuf; } avhdr =ubi_get_vid_hdr (avbuf);
@@ -1170,7 +1170,7 @@ static int ubi_write_fastmap(struct ubi_ seen_pebs =init_seen (ubi);if (IS_ERR (seen_pebs)) { ret =PTR_ERR (seen_pebs); - goto out_kfree; + goto out_free_dvbuf; }spin_lock (&ubi->volumes_lock);
@@ -1338,7 +1338,7 @@ static int ubi_write_fastmap(struct ubi_ ret =ubi_io_write_vid_hdr (ubi, new_fm->e[0 ]->pnum, avbuf);if (ret) {ubi_err (ubi,"unable to write vid_hdr to fastmap SB!" ); - goto out_kfree; + goto out_free_seen; }for (i =0 ; i < new_fm->used_blocks; i++) {
@@ -1360,7 +1360,7 @@ static int ubi_write_fastmap(struct ubi_if (ret) {ubi_err (ubi,"unable to write vid_hdr to PEB %i!" , new_fm->e[i]->pnum); - goto out_kfree; + goto out_free_seen; } }
@@ -1370,7 +1370,7 @@ static int ubi_write_fastmap(struct ubi_if (ret) {ubi_err (ubi,"unable to write fastmap to PEB %i!" , new_fm->e[i]->pnum); - goto out_kfree; + goto out_free_seen; } }
@@ -1380,10 +1380,13 @@ static int ubi_write_fastmap(struct ubi_ ret =self_check_seen (ubi, seen_pebs);dbg_bld ("fastmap written!" ); -out_kfree: -ubi_free_vid_buf (avbuf); -ubi_free_vid_buf (dvbuf); +out_free_seen:free_seen (seen_pebs); +out_free_dvbuf: +ubi_free_vid_buf (dvbuf); +out_free_avbuf: +ubi_free_vid_buf (avbuf); + out:return ret; }
Greg Kroah-Hartman
maintainerPATCH 111/173 mfd: rn5t618: Mark ADC control register volatile
In reply to Greg Kroah-HartmanFrom: Andreas Kemnade <[email protected]>
commit 2f3dc25c0118de03a00ddc88b61f7216854f534d upstream.
There is a bit which gets cleared after conversion.
--- drivers/mfd/rn5t618.c | 1 + 1 file changed, 1 insertion(+)
drivers/mfd/rn5t618.c +1 -0
@@ -32,6 +32,7 @@ static bool rn5t618_volatile_reg(structcase RN5T618_WATCHDOGCNT :case RN5T618_DCIRQ : case RN5T618_ILIMDATAH ... RN5T618_AIN0DATAL: +case RN5T618_ADCCNT3 : case RN5T618_IR_ADC1 ... RN5T618_IR_ADC3:case RN5T618_IR_GPR :case RN5T618_IR_GPF :
Greg Kroah-Hartman
maintainerPATCH 113/173 net_sched: fix a resource leak in tcindex_set_parms()
In reply to Greg Kroah-HartmanFrom: Cong Wang <[email protected]>
[ Upstream commit 52b5ae501c045010aeeb1d5ac0373ff161a88291 ]
Jakub noticed there is a potential resource leak in tcindex_set_parms(): when tcindex_filter_result_init() fails and it jumps to 'errout1' which doesn't release the memory and resources allocated by tcindex_alloc_perfect_hash().
We should just jump to 'errout_alloc' which callstcindex_free_perfect_hash().
--- net/sched/cls_tcindex.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
net/sched/cls_tcindex.c +1 -2
@@ -383,7 +383,7 @@ tcindex_set_parms(struct net *net, struc err =tcindex_filter_result_init (&new_filter_result);if (err <0 ) - goto errout1; + goto errout_alloc;if (old_r) cr = r->res;
@@ -502,7 +502,6 @@ errout_alloc:tcindex_free_perfect_hash (cp); else if (balloc == 2) kfree(cp->h); -errout1:tcf_exts_destroy (&new_filter_result.exts); errout:kfree (cp);
Greg Kroah-Hartman
maintainerPATCH 115/173 net: macb: Remove unnecessary alignment check for TSO
In reply to Greg Kroah-HartmanFrom: Harini Katakam <[email protected]>
[ Upstream commit 41c1ef978c8d0259c6636e6d2d854777e92650eb ]
The IP TSO implementation does NOT require the length to be a multiple of 8. That is only a requirement for UFO as per IP documentation. Hence, exit macb_features_check function in the beginning if the protocol is not UDP. Only when it is UDP, proceed further to the alignment checks. Update comments to reflect the same. Also remove dead code checking for protocol TCP when calculating header length.
--- drivers/net/ethernet/cadence/macb_main.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-)
drivers/net/ethernet/cadence/macb_main.c +3 -5
@@ -1577,16 +1577,14 @@ static netdev_features_t macb_features_c/* Validate LSO compatibility */ -/* there is only one buffer */ -if (!skb_is_nonlinear (skb)) +/* there is only one buffer or protocol is not UDP */ +if (!skb_is_nonlinear (skb) || (ip_hdr (skb)->protocol !=IPPROTO_UDP ))return features;/* length of header */ hdrlen =skb_transport_offset (skb); -if (ip_hdr (skb)->protocol ==IPPROTO_TCP ) - hdrlen +=tcp_hdrlen (skb); -/* For LSO: +/* For UFO only: * When software supplies two or more payload buffers all payload buffers * apart from the last must be a multiple of 8 bytes in size. */
Greg Kroah-Hartman
maintainerPATCH 146/173 PCI: Dont disable bridge BARs when assigning bus resources
In reply to Greg Kroah-HartmanFrom: Logan Gunthorpe <[email protected]>
commit 9db8dc6d0785225c42a37be7b44d1b07b31b8957 upstream.
Some PCI bridges implement BARs in addition to bridge windows. For example, here's a PLX switch:
04:00.0 PCI bridge: PLX Technology, Inc. PEX 8724 24-Lane, 6-Port PCI
Express Gen 3 (8 GT/s) Switch, 19 x 19mm FCBGA (rev ca) (prog-if 00 [Normal decode])
Flags: bus master, fast devsel, latency 0, IRQ 30, NUMA node 0 Memory at 90a00000 (32-bit, non-prefetchable) [size=256K]
Bus: primary=04, secondary=05, subordinate=0a, sec-latency=0 I/O behind bridge: 00002000-00003fff
Memory behind bridge: 90000000-909fffff
Prefetchable memory behind bridge: 0000380000800000-0000380000bfffff
Previously, when the kernel assigned resource addresses (with the pci=realloc command line parameter, for example) it could clear the struct resource corresponding to the BAR. When this happened, lspci would report this BAR as "ignored":
Region 0: Memory at <ignored> (32-bit, non-prefetchable) [size=256K]
This is because the kernel reports a zero start address and zero flags in the corresponding sysfs resource file and in /proc/bus/pci/devices. Investigation with 'lspci -x', however, shows the BIOS-assigned address will still be programmed in the device's BAR registers.
It's clearly a bug that the kernel lost track of the BAR value, but in most cases, this still won't result in a visible issue because nothing uses the memory, so nothing is affected. However, when an IOMMU is in use, it will not reserve this space in the IOVA because the kernel no longer thinks the range is valid. (See dmar_init_reserved_ranges() for the Intel implementation of this.)
Without the proper reserved range, a DMA mapping may allocate an IOVA that matches a bridge BAR, which results in DMA accesses going to the BAR instead of the intended RAM.
The problem was in pci_assign_unassigned_root_bus_resources(). When any resource from a bridge device fails to get assigned, the code set the resource's flags to zero. This makes sense for bridge windows, as they will be re-enabled later, but for regular BARs, it makes the kernel permanently lose track of the fact that they decode address space.
Change pci_assign_unassigned_root_bus_resources() and pci_assign_unassigned_bridge_resources() so they only clear "res->flags" for bridge *windows*, not bridge BARs.
--- drivers/pci/setup-bus.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-)
drivers/pci/setup-bus.c +16 -4
@@ -1824,12 +1824,18 @@ again:/* restore size and flags */ list_for_each_entry (fail_res, &fail_head, list) {struct resource *res = fail_res->res; +int idx; res->start = fail_res->start; res->end = fail_res->end; res->flags = fail_res->flags; -if (fail_res->dev->subordinate) - res->flags =0 ; + +if (pci_is_bridge (fail_res->dev)) { + idx = res - &fail_res->dev->resource[0 ]; +if (idx >=PCI_BRIDGE_RESOURCES && + idx <=PCI_BRIDGE_RESOURCE_END ) + res->flags =0 ; + } }free_list (&fail_head);
@@ -1895,12 +1901,18 @@ again:/* restore size and flags */ list_for_each_entry (fail_res, &fail_head, list) {struct resource *res = fail_res->res; +int idx; res->start = fail_res->start; res->end = fail_res->end; res->flags = fail_res->flags; -if (fail_res->dev->subordinate) - res->flags =0 ; + +if (pci_is_bridge (fail_res->dev)) { + idx = res - &fail_res->dev->resource[0 ]; +if (idx >=PCI_BRIDGE_RESOURCES && + idx <=PCI_BRIDGE_RESOURCE_END ) + res->flags =0 ; + } }free_list (&fail_head);
Greg Kroah-Hartman
maintainerPATCH 166/173 media: i2c: adv748x: Fix unsafe macros
In reply to Greg Kroah-HartmanFrom: Gustavo A. R. Silva <[email protected]>
commit 0d962e061abcf1b9105f88fb850158b5887fbca3 upstream.
Enclose multiple macro parameters in parentheses in order to make such macros safer and fix the Clang warning below:
drivers/media/i2c/adv748x/adv748x-afe.c:452:12: warning: operator '?:' has lower precedence than '|'; '|' will be evaluated first [-Wbitwise-conditional-parentheses]
ret = sdp_clrset(state, ADV748X_SDP_FRP, ADV748X_SDP_FRP_MASK, enable ? ctrl->val - 1 : 0);
--- drivers/media/i2c/adv748x/adv748x.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/media/i2c/adv748x/adv748x.h +4 -4
@@ -372,10 +372,10 @@ int adv748x_write_block(struct adv748x_s#define io_read (s, r) adv748x_read(s, ADV748X_PAGE_IO, r)#define io_write (s, r, v) adv748x_write(s, ADV748X_PAGE_IO, r, v) -#define io_clrset (s, r, m, v) io_write(s, r, (io_read(s, r) & ~m) | v) +#define io_clrset (s, r, m, v) io_write(s, r, (io_read(s, r) & ~(m)) | (v))#define hdmi_read (s, r) adv748x_read(s, ADV748X_PAGE_HDMI, r) -#define hdmi_read16 (s, r, m) (((hdmi_read(s, r) << 8) | hdmi_read(s, r+1)) & m) +#define hdmi_read16 (s, r, m) (((hdmi_read(s, r) << 8) | hdmi_read(s, (r)+1)) & (m))#define hdmi_write (s, r, v) adv748x_write(s, ADV748X_PAGE_HDMI, r, v)#define repeater_read (s, r) adv748x_read(s, ADV748X_PAGE_REPEATER, r)
@@ -383,11 +383,11 @@ int adv748x_write_block(struct adv748x_s#define sdp_read (s, r) adv748x_read(s, ADV748X_PAGE_SDP, r)#define sdp_write (s, r, v) adv748x_write(s, ADV748X_PAGE_SDP, r, v) -#define sdp_clrset (s, r, m, v) sdp_write(s, r, (sdp_read(s, r) & ~m) | v) +#define sdp_clrset (s, r, m, v) sdp_write(s, r, (sdp_read(s, r) & ~(m)) | (v))#define cp_read (s, r) adv748x_read(s, ADV748X_PAGE_CP, r)#define cp_write (s, r, v) adv748x_write(s, ADV748X_PAGE_CP, r, v) -#define cp_clrset (s, r, m, v) cp_write(s, r, (cp_read(s, r) & ~m) | v) +#define cp_clrset (s, r, m, v) cp_write(s, r, (cp_read(s, r) & ~(m)) | (v))#define txa_read (s, r) adv748x_read(s, ADV748X_PAGE_TXA, r)#define txb_read (s, r) adv748x_read(s, ADV748X_PAGE_TXB, r)
Greg Kroah-Hartman
maintainerPATCH 172/173 libertas: dont exit from lbs_ibss_join_existing() with RCU read lock held
In reply to Greg Kroah-HartmanFrom: Nicolai Stange <[email protected]>
[ Upstream commit c7bf1fb7ddca331780b9a733ae308737b39f1ad4 ]
Commit e5e884b42639 ("libertas: Fix two buffer overflows at parsing bss descriptor") introduced a bounds check on the number of supplied rates to lbs_ibss_join_existing().
Unfortunately, it introduced a return path from within a RCU read side critical section without a corresponding rcu_read_unlock(). Fix this.
--- drivers/net/wireless/marvell/libertas/cfg.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/wireless/marvell/libertas/cfg.c +1 -0
@@ -1788,6 +1788,7 @@ static int lbs_ibss_join_existing(struct lbs_private *priv, rates_max = rates_eid[1 ];if (rates_max >MAX_RATES ) {lbs_deb_join ("invalid rates" ); +rcu_read_unlock (); goto out; } rates = cmd.bss.rates;
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 173/173 libertas: make lbs_ibss_join_existing() return error code on rates overflow
In reply to Greg Kroah-HartmanFrom: Nicolai Stange <[email protected]>
[ Upstream commit 1754c4f60aaf1e17d886afefee97e94d7f27b4cb ]
Commit e5e884b42639 ("libertas: Fix two buffer overflows at parsing bss descriptor") introduced a bounds check on the number of supplied rates to lbs_ibss_join_existing() and made it to return on overflow.
However, the aforementioned commit doesn't set the return value accordingly and thus, lbs_ibss_join_existing() would return with zero even though it failed.
Make lbs_ibss_join_existing return -EINVAL in case the bounds check on the number of supplied rates fails.
--- drivers/net/wireless/marvell/libertas/cfg.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/wireless/marvell/libertas/cfg.c +1 -0
@@ -1789,6 +1789,7 @@ static int lbs_ibss_join_existing(struct lbs_private *priv,if (rates_max >MAX_RATES ) {lbs_deb_join ("invalid rates" );rcu_read_unlock (); + ret = -EINVAL ; goto out; } rates = cmd.bss.rates;
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 169/173 dm: fix potential for q->make_request_fn NULL pointer
In reply to Greg Kroah-HartmanFrom: Mike Snitzer <[email protected]>
commit 47ace7e012b9f7ad71d43ac9063d335ea3d6820b upstream.
Move blk_queue_make_request() to dm.c:alloc_dev() so that q->make_request_fn is never NULL during the lifetime of a DM device (even one that is created without a DM table).
Otherwise generic_make_request() will crash simply by doing:
dmsetup create -n test
mount /dev/dm-N /mnt
While at it, move ->congested_data initialization out of dm.c:alloc_dev() and into the bio-based specific init method.
Depends-on: c12c9a3c3860c ("dm: various cleanups to md->queue initialization code")
[smb: adjusted for context and dm_init_md_queue() exitsting in older
kernels]
--- drivers/md/dm.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/md/dm.c +7 -2
@@ -1647,7 +1647,6 @@ void dm_init_md_queue(struct mapped_devi* - must do so here (in alloc_dev callchain) before queue is used */ md->queue->queuedata = md; - md->queue->backing_dev_info->congested_data = md; }void dm_init_normal_md_queue (struct mapped_device *md)
@@ -1658,6 +1657,7 @@ void dm_init_normal_md_queue(struct mapp/* * Initialize aspects of queue that aren't relevant for blk-mq */ + md->queue->backing_dev_info->congested_data = md; md->queue->backing_dev_info->congested_fn = dm_any_congested; }
@@ -1750,6 +1750,12 @@ static struct mapped_device *alloc_dev(i goto bad;dm_init_md_queue (md); +/* +* default to bio-based required ->make_request_fn until DM +* table is loaded and md->type established. If request-based +* table is loaded: blk-mq will override accordingly. +*/ +blk_queue_make_request (md->queue, dm_make_request); md->disk =alloc_disk_node (1 , numa_node_id);if (!md->disk)
@@ -2055,7 +2061,6 @@ int dm_setup_md_queue(struct mapped_devicase DM_TYPE_BIO_BASED :case DM_TYPE_DAX_BIO_BASED :dm_init_normal_md_queue (md); -blk_queue_make_request (md->queue, dm_make_request);/* * DM handles splitting bios as needed. Free the bio_split bioset * since it won't be used (saves 1 process per bio-based DM device).
Greg Kroah-Hartman
maintainerPATCH 152/173 rtc: cmos: Stop using shared IRQ
In reply to Greg Kroah-HartmanFrom: Andy Shevchenko <[email protected]>
commit b6da197a2e9670df6f07e6698629e9ce95ab614e upstream.
As reported by Guilherme G. Piccoli:
---8<---8<---8<---
The rtc-cmos interrupt setting was changed in the commit 079062b28fb4 ("rtc: cmos: prevent kernel warning on IRQ flags mismatch") in order to allow shared interrupts; according to that commit's description, some machine got kernel warnings due to the interrupt line being shared between rtc-cmos and other hardware, and rtc-cmos didn't allow IRQ sharing that time.
After the aforementioned commit though it was observed a huge increase in lost HPET interrupts in some systems, observed through the following kernel message:
[...] hpet1: lost 35 rtc interrupts
After investigation, it was narrowed down to the shared interrupts usage when having the kernel option "irqpoll" enabled. In this case, all IRQ handlers are called for non-timer interrupts, if such handlers are setup in shared IRQ lines. The rtc-cmos IRQ handler could be set to hpet_rtc_interrupt(), which will produce the kernel "lost interrupts" message after doing work - lots of readl/writel to HPET registers, which are known to be slow.
Although "irqpoll" is not a default kernel option, it's used in some contexts, one being the kdump kernel (which is an already "impaired" kernel usually running with 1 CPU available), so the performance burden could be considerable. Also, the same issue would happen (in a shorter extent though) when using "irqfixup" kernel option.
In a quick experiment, a virtual machine with uptime of 2 minutes produced
Quoted 1 line
300 calls to
hpet_rtc_interrupt()when "irqpoll" was set, whereas without
sharing interrupts this number reduced to 1 interrupt. Machines with more hardware than a VM should generate even more unnecessary HPET interrupts in this scenario.
---8<---8<---8<---
After looking into the rtc-cmos driver history and DSDT table from the Microsoft Surface 3, we may notice that Hans de Goede submitted a correct fix (see dependency below). Thus, we simply revert the culprit commit.
Depends-on: a1e23a42f1bd ("rtc: cmos: Do not assume irq 8 for rtc when there are no legacy irqs")
--- drivers/rtc/rtc-cmos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/rtc/rtc-cmos.c +1 -1
@@ -806,7 +806,7 @@ cmos_do_probe(struct device *dev, struct rtc_cmos_int_handler = cmos_interrupt; retval =request_irq (rtc_irq, rtc_cmos_int_handler, -IRQF_SHARED ,dev_name (&cmos_rtc.rtc->dev), +0 ,dev_name (&cmos_rtc.rtc->dev), cmos_rtc.rtc);if (retval <0 ) {dev_dbg (dev,"IRQ %d is already in use\n" , rtc_irq);
Greg Kroah-Hartman
maintainerPATCH 127/173 drm/dp_mst: Remove VCPI while disabling topology mgr
In reply to Greg Kroah-HartmanFrom: Wayne Lin <[email protected]>
[ Upstream commit 64e62bdf04ab8529f45ed0a85122c703035dec3a ]
[Why]
This patch is trying to address the issue observed when hotplug DP daisy chain monitors.
e.g.
src-mstb-mstb-sst -> src (unplug) mstb-mstb-sst -> src-mstb-mstb-sst (plug in again)
Once unplug a DP MST capable device, driver will call drm_dp_mst_topology_mgr_set_mst() to disable MST. In this function, it cleans data of topology manager while disabling mst_state. However, it doesn't clean up the proposed_vcpis of topology manager. If proposed_vcpi is not reset, once plug in MST daisy chain monitors later, code will fail at checking port validation while trying to allocate payloads.
When MST capable device is plugged in again and try to allocate payloads by calling drm_dp_update_payload_part1(), this function will iterate over all proposed virtual channels to see if any proposed VCPI's num_slots is greater than 0. If any proposed VCPI's num_slots is greater than 0 and the port which the specific virtual channel directed to is not in the topology, code then fails at the port validation. Since there are stale VCPI allocations from the previous topology enablement in proposed_vcpi[], code will fail at port validation and reurn EINVAL.
[How]
Clean up the data of stale proposed_vcpi[] and reset mgr->proposed_vcpis to NULL while disabling mst in drm_dp_mst_topology_mgr_set_mst().
Changes since v1:
*Add on more details in commit message to describe the issue which the patch is trying to fix
--- drivers/gpu/drm/drm_dp_mst_topology.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/gpu/drm/drm_dp_mst_topology.c +12 -0
@@ -2046,6 +2046,7 @@ static bool drm_dp_get_vc_payload_bw(int dp_link_bw,int drm_dp_mst_topology_mgr_set_mst (struct drm_dp_mst_topology_mgr *mgr,bool mst_state) {int ret =0 ; +int i =0 ;struct drm_dp_mst_branch *mstb =NULL ;mutex_lock (&mgr->lock);
@@ -2106,10 +2107,21 @@ int drm_dp_mst_topology_mgr_set_mst(struct drm_dp_mst_topology_mgr *mgr, bool ms/* this can fail if the device is gone */ drm_dp_dpcd_writeb (mgr->aux,DP_MSTM_CTRL ,0 ); ret =0 ; +mutex_lock (&mgr->payload_lock);memset (mgr->payloads,0 , mgr->max_payloads *sizeof (struct drm_dp_payload )); mgr->payload_mask =0 ;set_bit (0 , &mgr->payload_mask); +for (i =0 ; i < mgr->max_payloads; i++) { +struct drm_dp_vcpi *vcpi = mgr->proposed_vcpis[i]; + +if (vcpi) { + vcpi->vcpi =0 ; + vcpi->num_slots =0 ; + } + mgr->proposed_vcpis[i] =NULL ; + } mgr->vcpi_mask =0 ; +mutex_unlock (&mgr->payload_lock); } out_unlock:
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 141/173 ASoC: pcm: update FE/BE trigger order based on the command
In reply to Greg Kroah-HartmanFrom: Ranjani Sridharan <[email protected]>
[ Upstream commit acbf27746ecfa96b290b54cc7f05273482ea128a ]
Currently, the trigger orders SND_SOC_DPCM_TRIGGER_PRE/POST determine the order in which FE DAI and BE DAI are triggered. In the case of SND_SOC_DPCM_TRIGGER_PRE, the FE DAI is triggered before the BE DAI and in the case of SND_SOC_DPCM_TRIGGER_POST, the BE DAI is triggered before the FE DAI. And this order remains the same irrespective of the trigger command.
In the case of the SOF driver, during playback, the FW expects the BE DAI to be triggered before the FE DAI during the START trigger. The BE DAI trigger handles the starting of Link DMA and so it must be started before the FE DAI is started to prevent xruns during pause/release. This can be addressed by setting the trigger order for the FE dai link to SND_SOC_DPCM_TRIGGER_POST. But during the STOP trigger, the FW expects the FE DAI to be triggered before the BE DAI. Retaining the same order during the START and STOP commands, results in FW error as the DAI component in the FW is still active.
The issue can be fixed by mirroring the trigger order of FE and BE DAI's during the START and STOP trigger. So, with the trigger order set to SND_SOC_DPCM_TRIGGER_PRE, the FE DAI will be trigger first during SNDRV_PCM_TRIGGER_START/STOP/RESUME and the BE DAI will be triggered first during the STOP/SUSPEND/PAUSE commands. Conversely, with the trigger order set to SND_SOC_DPCM_TRIGGER_POST, the BE DAI will be triggered first during the SNDRV_PCM_TRIGGER_START/STOP/RESUME commands and the FE DAI will be triggered first during the SNDRV_PCM_TRIGGER_STOP/SUSPEND/PAUSE commands.
--- sound/soc/soc-pcm.c | 95 ++++++++++++++++++++++++++++++++------------- 1 file changed, 68 insertions(+), 27 deletions(-)
sound/soc/soc-pcm.c +68 -27
@@ -2123,42 +2123,81 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, }EXPORT_SYMBOL_GPL (dpcm_be_dai_trigger); +static int dpcm_dai_trigger_fe_be (struct snd_pcm_substream *substream, +int cmd,bool fe_first) +{ +struct snd_soc_pcm_runtime *fe = substream->private_data; +int ret; + +/* call trigger on the frontend before the backend. */ +if (fe_first) { +dev_dbg (fe->dev,"ASoC: pre trigger FE %s cmd %d\n" , + fe->dai_link->name, cmd); + + ret =soc_pcm_trigger (substream, cmd); +if (ret <0 ) +return ret; + + ret =dpcm_be_dai_trigger (fe, substream->stream, cmd); +return ret; + } + +/* call trigger on the frontend after the backend. */ + ret =dpcm_be_dai_trigger (fe, substream->stream, cmd); +if (ret <0 ) +return ret; + +dev_dbg (fe->dev,"ASoC: post trigger FE %s cmd %d\n" , + fe->dai_link->name, cmd); + + ret =soc_pcm_trigger (substream, cmd); + +return ret; +} +static int dpcm_fe_dai_do_trigger (struct snd_pcm_substream *substream,int cmd) {struct snd_soc_pcm_runtime *fe = substream->private_data; -int stream = substream->stream, ret; +int stream = substream->stream; +int ret =0 ;enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; fe->dpcm[stream].runtime_update =SND_SOC_DPCM_UPDATE_FE ;switch (trigger) {case SND_SOC_DPCM_TRIGGER_PRE : -/* call trigger on the frontend before the backend. */ - -dev_dbg (fe->dev,"ASoC: pre trigger FE %s cmd %d\n" , - fe->dai_link->name, cmd); - - ret =soc_pcm_trigger (substream, cmd); -if (ret <0 ) { -dev_err (fe->dev,"ASoC: trigger FE failed %d\n" , ret); - goto out; +switch (cmd) { +case SNDRV_PCM_TRIGGER_START : +case SNDRV_PCM_TRIGGER_RESUME : +case SNDRV_PCM_TRIGGER_PAUSE_RELEASE : + ret =dpcm_dai_trigger_fe_be (substream, cmd, true); +break ; +case SNDRV_PCM_TRIGGER_STOP : +case SNDRV_PCM_TRIGGER_SUSPEND : +case SNDRV_PCM_TRIGGER_PAUSE_PUSH : + ret =dpcm_dai_trigger_fe_be (substream, cmd, false); +break ; +default : + ret = -EINVAL ; +break ; } - - ret =dpcm_be_dai_trigger (fe, substream->stream, cmd);break ;case SND_SOC_DPCM_TRIGGER_POST : -/* call trigger on the frontend after the backend. */ - - ret =dpcm_be_dai_trigger (fe, substream->stream, cmd); -if (ret <0 ) { -dev_err (fe->dev,"ASoC: trigger FE failed %d\n" , ret); - goto out; +switch (cmd) { +case SNDRV_PCM_TRIGGER_START : +case SNDRV_PCM_TRIGGER_RESUME : +case SNDRV_PCM_TRIGGER_PAUSE_RELEASE : + ret =dpcm_dai_trigger_fe_be (substream, cmd, false); +break ; +case SNDRV_PCM_TRIGGER_STOP : +case SNDRV_PCM_TRIGGER_SUSPEND : +case SNDRV_PCM_TRIGGER_PAUSE_PUSH : + ret =dpcm_dai_trigger_fe_be (substream, cmd, true); +break ; +default : + ret = -EINVAL ; +break ; } - -dev_dbg (fe->dev,"ASoC: post trigger FE %s cmd %d\n" , - fe->dai_link->name, cmd); - - ret =soc_pcm_trigger (substream, cmd);break ;case SND_SOC_DPCM_TRIGGER_BESPOKE :/* bespoke trigger() - handles both FE and BEs */
@@ -2167,10 +2206,6 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) fe->dai_link->name, cmd); ret =soc_pcm_bespoke_trigger (substream, cmd); -if (ret <0 ) { -dev_err (fe->dev,"ASoC: trigger FE failed %d\n" , ret); - goto out; - }break ;default : dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd,
@@ -2179,6 +2214,12 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) goto out; } +if (ret <0 ) { +dev_err (fe->dev,"ASoC: trigger FE cmd: %d failed: %d\n" , + cmd, ret); + goto out; + } +switch (cmd) {case SNDRV_PCM_TRIGGER_START :case SNDRV_PCM_TRIGGER_RESUME :
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 138/173 clocksource: Prevent double add_timer_on() for watchdog_timer
In reply to Greg Kroah-HartmanFrom: Konstantin Khlebnikov <[email protected]>
commit febac332a819f0e764aa4da62757ba21d18c182b upstream.
Kernel crashes inside QEMU/KVM are observed:
kernel BUG at kernel/time/timer.c:1154! BUG_ON(timer_pending(timer) || !timer->function) in add_timer_on().
At the same time another cpu got:
general protection fault: 0000 [#1] SMP PTI of poinson pointer 0xdead000000000200 in:
__hlist_del at include/linux/list.h:681
(inlined by) detach_timer at kernel/time/timer.c:818 (inlined by) expire_timers at kernel/time/timer.c:1355 (inlined by) __run_timers at kernel/time/timer.c:1686 (inlined by) run_timer_softirq at kernel/time/timer.c:1699
Unfortunately kernel logs are badly scrambled, stacktraces are lost.
Printing the timer->function before the BUG_ON() pointed to clocksource_watchdog().
The execution of clocksource_watchdog() can race with a sequence of clocksource_stop_watchdog() .. clocksource_start_watchdog():
expire_timers()
detach_timer(timer, true);
timer->entry.pprev = NULL;
raw_spin_unlock_irq(&base->lock);
call_timer_fn
clocksource_watchdog()
clocksource_watchdog_kthread() or clocksource_unbind() spin_lock_irqsave(&watchdog_lock, flags); clocksource_stop_watchdog(); del_timer(&watchdog_timer); watchdog_running = 0; spin_unlock_irqrestore(&watchdog_lock, flags); spin_lock_irqsave(&watchdog_lock, flags); clocksource_start_watchdog(); add_timer_on(&watchdog_timer, ...); watchdog_running = 1; spin_unlock_irqrestore(&watchdog_lock, flags);
spin_lock(&watchdog_lock);
add_timer_on(&watchdog_timer, ...);
BUG_ON(timer_pending(timer) || !timer->function);
timer_pending() -> true
BUG()I.e. inside clocksource_watchdog() watchdog_timer could be already armed.
Check timer_pending() before calling add_timer_on(). This is sufficient as all operations are synchronized by watchdog_lock.
--- kernel/time/clocksource.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
kernel/time/clocksource.c +9 -2
@@ -280,8 +280,15 @@ static void clocksource_watchdog(unsigne next_cpu =cpumask_next (raw_smp_processor_id (), cpu_online_mask);if (next_cpu >= nr_cpu_ids) next_cpu =cpumask_first (cpu_online_mask); - watchdog_timer.expires +=WATCHDOG_INTERVAL ; -add_timer_on (&watchdog_timer, next_cpu); + +/* +* Arm timer if not already pending: could race with concurrent +* pair clocksource_stop_watchdog() clocksource_start_watchdog(). +*/ +if (!timer_pending (&watchdog_timer)) { + watchdog_timer.expires +=WATCHDOG_INTERVAL ; +add_timer_on (&watchdog_timer, next_cpu); + } out:spin_unlock (&watchdog_lock); }
Greg Kroah-Hartman
maintainerPATCH 110/173 mfd: da9062: Fix watchdog compatible string
In reply to Greg Kroah-HartmanFrom: Marco Felsch <[email protected]>
commit 1112ba02ff1190ca9c15a912f9269e54b46d2d82 upstream.
The watchdog driver compatible is "dlg,da9062-watchdog" and not "dlg,da9062-wdt". Therefore the mfd-core can't populate the of_node and fwnode. As result the watchdog driver can't parse the devicetree.
--- drivers/mfd/da9062-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mfd/da9062-core.c +1 -1
@@ -257,7 +257,7 @@ static const struct mfd_cell da9062_devs .name = "da9062-watchdog", .num_resources = ARRAY_SIZE(da9062_wdt_resources), .resources = da9062_wdt_resources, - .of_compatible = "dlg,da9062-wdt", + .of_compatible = "dlg,da9062-watchdog", }, { .name = "da9062-thermal",
Greg Kroah-Hartman
maintainerPATCH 123/173 btrfs: free block groups after freeing fs trees
In reply to Greg Kroah-HartmanFrom: Josef Bacik <[email protected]>
[ Upstream commit 4e19443da1941050b346f8fc4c368aa68413bc88 ]
Sometimes when running generic/475 we would trip the WARN_ON(cache->reserved) check when free'ing the block groups on umount. This is because sometimes we don't commit the transaction because of IO errors and thus do not cleanup the tree logs until at umount time.
These blocks are still reserved until they are cleaned up, but they aren't cleaned up until _after_ we do the free block groups work. Fix this by moving the free after free'ing the fs roots, that way all of the tree logs are cleaned up and we have a properly cleaned fs. A bunch of loops of generic/475 confirmed this fixes the problem.
--- fs/btrfs/disk-io.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
fs/btrfs/disk-io.c +9 -2
@@ -3761,11 +3761,18 @@ void close_ctree(struct btrfs_fs_info *fs_info)invalidate_inode_pages2 (fs_info->btree_inode->i_mapping);btrfs_stop_all_workers (fs_info); -btrfs_free_block_groups (fs_info); -clear_bit (BTRFS_FS_OPEN , &fs_info->flags);free_root_pointers (fs_info, true); +/* +* We must free the block groups after dropping the fs_roots as we could +* have had an IO error and have left over tree log blocks that aren't +* cleaned up until the fs roots are freed. This makes the block group +* accounting appear to be wrong because there's pending reserved bytes, +* so make sure we do the block group cleanup afterwards. +*/ +btrfs_free_block_groups (fs_info); +iput (fs_info->btree_inode);#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 91/173 KVM: x86: Free wbinvd_dirty_mask if vCPU creation fails
In reply to Greg Kroah-HartmanFrom: Sean Christopherson <[email protected]>
commit 16be9ddea268ad841457a59109963fff8c9de38d upstream.
Free the vCPU's wbinvd_dirty_mask if vCPU creation fails after kvm_arch_vcpu_init(), e.g. when installing the vCPU's file descriptor. Do the freeing by calling kvm_arch_vcpu_free() instead of open coding the freeing. This adds a likely superfluous, but ultimately harmless, call to kvmclock_reset(), which only clears vcpu->arch.pv_time_enabled. Using kvm_arch_vcpu_free() allows for additional cleanup in the future.
--- arch/x86/kvm/x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kvm/x86.c +1 -1
@@ -8063,7 +8063,7 @@ void kvm_arch_vcpu_destroy(struct kvm_vckvm_mmu_unload (vcpu);vcpu_put (vcpu); - kvm_x86_ops->vcpu_free (vcpu); +kvm_arch_vcpu_free (vcpu); }void kvm_vcpu_reset (struct kvm_vcpu *vcpu,bool init_event)
Greg Kroah-Hartman
maintainerPATCH 94/173 scsi: csiostor: Adjust indentation in csio_device_reset
In reply to Greg Kroah-HartmanFrom: Nathan Chancellor <[email protected]>
commit a808a04c861782e31fc30e342a619c144aaee14a upstream.
Clang warns:
../drivers/scsi/csiostor/csio_scsi.c:1386:3: warning: misleading indentation; statement is not part of the previous 'if' [-Wmisleading-indentation]
csio_lnodes_exit(hw, 1);
^
../drivers/scsi/csiostor/csio_scsi.c:1382:2: note: previous statement is
here
if (*buf != '1')
^1 warning generated.
This warning occurs because there is a space after the tab on this line. Remove it so that the indentation is consistent with the Linux kernel coding style and clang no longer warns.
--- drivers/scsi/csiostor/csio_scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/scsi/csiostor/csio_scsi.c +1 -1
@@ -1383,7 +1383,7 @@ csio_device_reset(struct device *dev,return -EINVAL ;/* Delete NPIV lnodes */ -csio_lnodes_exit (hw,1 ); +csio_lnodes_exit (hw,1 );/* Block upper IOs */ csio_lnodes_block_request (hw);
Greg Kroah-Hartman
maintainerPATCH 69/173 NFS: Fix memory leaks and corruption in readdir
In reply to Greg Kroah-HartmanFrom: Trond Myklebust <[email protected]>
commit 4b310319c6a8ce708f1033d57145e2aa027a883c upstream.
nfs_readdir_xdr_to_array() must not exit without having initialised the array, so that the page cache deletion routines can safely call nfs_readdir_clear_array().
Furthermore, we should ensure that if we exit nfs_readdir_filler() with an error, we free up any page contents to prevent a leak if we try to fill the page again.
--- fs/nfs/dir.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
fs/nfs/dir.c +15 -2
@@ -169,6 +169,17 @@ typedef struct {bool eof; } nfs_readdir_descriptor_t; +static +void nfs_readdir_init_array (struct page *page) +{ +struct nfs_cache_array *array; + + array =kmap_atomic (page); +memset (array,0 ,sizeof (struct nfs_cache_array )); + array->eof_index =-1 ; +kunmap_atomic (array); +} +/* * we are freeing strings created by nfs_add_to_readdir_array() */
@@ -181,6 +192,7 @@ void nfs_readdir_clear_array(struct page array =kmap_atomic (page);for (i =0 ; i < array->size; i++)kfree (array->array[i].string.name); + array->size =0 ;kunmap_atomic (array); }
@@ -617,6 +629,8 @@ int nfs_readdir_xdr_to_array(nfs_readdirint status = -ENOMEM ;unsigned int array_size =ARRAY_SIZE (pages); +nfs_readdir_init_array (page); + entry.prev_cookie =0 ; entry.cookie = desc->last_cookie; entry.eof =0 ;
@@ -633,8 +647,6 @@ int nfs_readdir_xdr_to_array(nfs_readdir } array =kmap (page); -memset (array,0 ,sizeof (struct nfs_cache_array )); - array->eof_index =-1 ; status =nfs_readdir_alloc_pages (pages, array_size);if (status <0 )
@@ -688,6 +700,7 @@ int nfs_readdir_filler(nfs_readdir_descrunlock_page (page);return 0 ; error: +nfs_readdir_clear_array (page);unlock_page (page);return ret; }
Greg Kroah-Hartman
maintainerPATCH 71/173 btrfs: set trans->drity in btrfs_commit_transaction
In reply to Greg Kroah-HartmanFrom: Josef Bacik <[email protected]>
commit d62b23c94952e78211a383b7d90ef0afbd9a3717 upstream.
If we abort a transaction we have the following sequence
if (!trans->dirty && list_empty(&trans->new_bgs))
return;
WRITE_ONCE(trans->transaction->aborted, err);
The idea being if we didn't modify anything with our trans handle then we don't really need to abort the whole transaction, maybe the other trans handles are fine and we can carry on.
However in the case of create_snapshot we add a pending_snapshot object to our transaction and then commit the transaction. We don't actually modify anything. sync() behaves the same way, attach to an existing transaction and commit it. This means that if we have an IO error in the right places we could abort the committing transaction with our trans->dirty being not set and thus not set transaction->aborted.
This is a problem because in the create_snapshot() case we depend on pending->error being set to something, or btrfs_commit_transaction returning an error.
If we are not the trans handle that gets to commit the transaction, and we're waiting on the commit to happen we get our return value from cur_trans->aborted. If this was not set to anything because sync() hit an error in the transaction commit before it could modify anything then cur_trans->aborted would be 0. Thus we'd return 0 from btrfs_commit_transaction() in create_snapshot.
This is a problem because we then try to do things with pending_snapshot->snap, which will be NULL because we didn't create the snapshot, and then we'll get a NULL pointer dereference like the following
"BUG: kernel NULL pointer dereference, address: 00000000000001f0"
RIP: 0010:btrfs_orphan_cleanup+0x2d/0x330 Call Trace: ? btrfs_mksubvol.isra.31+0x3f2/0x510 btrfs_mksubvol.isra.31+0x4bc/0x510 ? __sb_start_write+0xfa/0x200 ? mnt_want_write_file+0x24/0x50 btrfs_ioctl_snap_create_transid+0x16c/0x1a0 btrfs_ioctl_snap_create_v2+0x11e/0x1a0 btrfs_ioctl+0x1534/0x2c10 ? free_debug_processing+0x262/0x2a3 do_vfs_ioctl+0xa6/0x6b0 ? do_sys_open+0x188/0x220 ? syscall_trace_enter+0x1f8/0x330 ksys_ioctl+0x60/0x90 __x64_sys_ioctl+0x16/0x20 do_syscall_64+0x4a/0x1b0
In order to fix this we need to make sure anybody who calls commit_transaction has trans->dirty set so that they properly set the trans->transaction->aborted value properly so any waiters know bad things happened.
This was found while I was running generic/475 with my modified fsstress, it reproduced within a few runs. I ran with this patch all night and didn't see the problem again.
--- fs/btrfs/transaction.c | 8 ++++++++ 1 file changed, 8 insertions(+)
fs/btrfs/transaction.c +8 -0
@@ -1948,6 +1948,14 @@ int btrfs_commit_transaction(struct btrfstruct btrfs_transaction *prev_trans =NULL ;int ret; +/* +* Some places just start a transaction to commit it. We need to make +* sure that if this commit fails that the abort code actually marks the +* transaction as failed, so set trans->dirty to make the abort code do +* the right thing. +*/ + trans->dirty = true; +/* Stop the commit early if ->aborted is set */ if (unlikely (READ_ONCE (cur_trans->aborted))) { ret = cur_trans->aborted;
Greg Kroah-Hartman
maintainerPATCH 85/173 KVM: x86: Protect ioapic_read_indirect() from Spectre-v1/L1TF attacks
In reply to Greg Kroah-HartmanFrom: Marios Pomonis <[email protected]>
commit 8c86405f606ca8508b8d9280680166ca26723695 upstream.
This fixes a Spectre-v1/L1TF vulnerability in ioapic_read_indirect(). This function contains index computations based on the (attacker-controlled) IOREGSEL register.
--- arch/x86/kvm/ioapic.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-)
arch/x86/kvm/ioapic.c +8 -6
@@ -36,6 +36,7 @@#include <linux/io.h> #include <linux/slab.h> #include <linux/export.h> +#include <linux/nospec.h> #include <asm/processor.h> #include <asm/page.h> #include <asm/current.h>
@@ -73,13 +74,14 @@ static unsigned long ioapic_read_indirecdefault : {u32 redir_index = (ioapic->ioregsel -0x10 ) >>1 ; -u64 redir_content; +u64 redir_content = ~0ULL ; -if (redir_index <IOAPIC_NUM_PINS ) - redir_content = - ioapic->redirtbl[redir_index].bits; -else - redir_content = ~0ULL ; +if (redir_index <IOAPIC_NUM_PINS ) { +u32 index =array_index_nospec ( + redir_index,IOAPIC_NUM_PINS ); + + redir_content = ioapic->redirtbl[index].bits; + } result = (ioapic->ioregsel &0x1 ) ? (redir_content >> 32) & 0xffffffff :
Greg Kroah-Hartman
maintainerPATCH 84/173 KVM: x86: Protect MSR-based index computations in pmu.h from Spectre-v1/L1TF attacks
In reply to Greg Kroah-HartmanFrom: Marios Pomonis <[email protected]>
commit 13c5183a4e643cc2b03a22d0e582c8e17bb7457d upstream.
This fixes a Spectre-v1/L1TF vulnerability in the get_gp_pmc() and get_fixed_pmc() functions.
They both contain index computations based on the (attacker-controlled) MSR number.
--- arch/x86/kvm/pmu.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
arch/x86/kvm/pmu.h +14 -4
@@ -2,6 +2,8 @@#ifndef __KVM_X86_PMU_H#define __KVM_X86_PMU_H +#include <linux/nospec.h> +#define vcpu_to_pmu (vcpu) (&(vcpu)->arch.pmu)#define pmu_to_vcpu (pmu) (container_of((pmu), struct kvm_vcpu, arch.pmu))#define pmc_to_pmu (pmc) (&(pmc)->vcpu->arch.pmu)
@@ -81,8 +83,12 @@ static inline bool pmc_is_enabled(structstatic inline struct kvm_pmc *get_gp_pmc (struct kvm_pmu *pmu,u32 msr,u32 base) { -if (msr >= base && msr < base + pmu->nr_arch_gp_counters) -return &pmu->gp_counters[msr - base]; +if (msr >= base && msr < base + pmu->nr_arch_gp_counters) { +u32 index =array_index_nospec (msr - base, + pmu->nr_arch_gp_counters); + +return &pmu->gp_counters[index]; + }return NULL ; }
@@ -92,8 +98,12 @@ static inline struct kvm_pmc *get_fixed_ {int base =MSR_CORE_PERF_FIXED_CTR0 ; -if (msr >= base && msr < base + pmu->nr_arch_fixed_counters) -return &pmu->fixed_counters[msr - base]; +if (msr >= base && msr < base + pmu->nr_arch_fixed_counters) { +u32 index =array_index_nospec (msr - base, + pmu->nr_arch_fixed_counters); + +return &pmu->fixed_counters[index]; + }return NULL ; }
Greg Kroah-Hartman
maintainerPATCH 55/173 dm space map common: fix to ensure new block isnt already in use
In reply to Greg Kroah-HartmanFrom: Joe Thornber <[email protected]>
commit 4feaef830de7ffdd8352e1fe14ad3bf13c9688f8 upstream.
The space-maps track the reference counts for disk blocks allocated by both the thin-provisioning and cache targets. There are variants for tracking metadata blocks and data blocks.
Transactionality is implemented by never touching blocks from the previous transaction, so we can rollback in the event of a crash.
When allocating a new block we need to ensure the block is free (has reference count of 0) in both the current and previous transaction. Prior to this fix we were doing this by searching for a free block in the previous transaction, and relying on a 'begin' counter to track where the last allocation in the current transaction was. This 'begin' field was not being updated in all code paths (eg, increment of a data block reference count due to breaking sharing of a neighbour block in the same btree leaf).
This fix keeps the 'begin' field, but now it's just a hint to speed up the search. Instead the current transaction is searched for a free block, and then the old transaction is double checked to ensure it's free. Much simpler.
This fixes reports of sm_disk_new_block()'s BUG_ON() triggering when DM thin-provisioning's snapshots are heavily used.
--- drivers/md/persistent-data/dm-space-map-common.c | 27 +++++++++++++++++++++ drivers/md/persistent-data/dm-space-map-common.h | 2 + drivers/md/persistent-data/dm-space-map-disk.c | 6 +++- drivers/md/persistent-data/dm-space-map-metadata.c | 5 +++ 4 files changed, 37 insertions(+), 3 deletions(-)
drivers/md/persistent-data/dm-space-map-common.c +27 -0
@@ -382,6 +382,33 @@ int sm_ll_find_free_block(struct ll_diskreturn -ENOSPC ; } +int sm_ll_find_common_free_block (struct ll_disk *old_ll,struct ll_disk *new_ll, +dm_block_t begin,dm_block_t end,dm_block_t *b) +{ +int r; +uint32_t count; + +do { + r =sm_ll_find_free_block (new_ll, begin, new_ll->nr_blocks, b); +if (r) +break ; + +/* double check this block wasn't used in the old transaction */ +if (*b >= old_ll->nr_blocks) + count =0 ; +else { + r =sm_ll_lookup (old_ll, *b, &count); +if (r) +break ; + +if (count) + begin = *b +1 ; + } + }while (count); + +return r; +} +static int sm_ll_mutate (struct ll_disk *ll,dm_block_t b,int (*mutator)(void *context,uint32_t old,uint32_t *new),void *context,enum allocation_event *ev)
drivers/md/persistent-data/dm-space-map-common.h +2 -0
@@ -109,6 +109,8 @@ int sm_ll_lookup_bitmap(struct ll_disk *int sm_ll_lookup (struct ll_disk *ll,dm_block_t b,uint32_t *result);int sm_ll_find_free_block (struct ll_disk *ll,dm_block_t begin,dm_block_t end,dm_block_t *result); +int sm_ll_find_common_free_block (struct ll_disk *old_ll,struct ll_disk *new_ll, +dm_block_t begin,dm_block_t end,dm_block_t *result);int sm_ll_insert (struct ll_disk *ll,dm_block_t b,uint32_t ref_count,enum allocation_event *ev);int sm_ll_inc (struct ll_disk *ll,dm_block_t b,enum allocation_event *ev);int sm_ll_dec (struct ll_disk *ll,dm_block_t b,enum allocation_event *ev);
drivers/md/persistent-data/dm-space-map-disk.c +4 -2
@@ -167,8 +167,10 @@ static int sm_disk_new_block(struct dm_senum allocation_event ev; struct sm_disk *smd = container_of(sm, struct sm_disk, sm); -/* FIXME: we should loop round a couple of times */ - r =sm_ll_find_free_block (&smd->old_ll, smd->begin, smd->old_ll.nr_blocks, b); +/* +* Any block we allocate has to be free in both the old and current ll. +*/ + r =sm_ll_find_common_free_block (&smd->old_ll, &smd->ll, smd->begin, smd->ll.nr_blocks, b);if (r)return r;
drivers/md/persistent-data/dm-space-map-metadata.c +4 -1
@@ -447,7 +447,10 @@ static int sm_metadata_new_block_(structenum allocation_event ev; struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm); - r =sm_ll_find_free_block (&smm->old_ll, smm->begin, smm->old_ll.nr_blocks, b); +/* +* Any block we allocate has to be free in both the old and current ll. +*/ + r =sm_ll_find_common_free_block (&smm->old_ll, &smm->ll, smm->begin, smm->ll.nr_blocks, b);if (r)return r;
Greg Kroah-Hartman
maintainerPATCH 59/173 tracing: Annotate ftrace_graph_notrace_hash pointer with __rcu
In reply to Greg Kroah-HartmanFrom: Amol Grover <[email protected]>
[ Upstream commit fd0e6852c407dd9aefc594f54ddcc21d84803d3b ]
Fix following instances of sparse error kernel/trace/ftrace.c:5667:29: error: incompatible types in comparison kernel/trace/ftrace.c:5813:21: error: incompatible types in comparison kernel/trace/ftrace.c:5868:36: error: incompatible types in comparison kernel/trace/ftrace.c:5870:25: error: incompatible types in comparison
Use rcu_dereference_protected to dereference the newly annotated pointer.
--- kernel/trace/ftrace.c | 2 +- kernel/trace/trace.h | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-)
kernel/trace/ftrace.c +1 -1
@@ -5147,7 +5147,7 @@ static const struct file_operations ftrace_notrace_fops = {static DEFINE_MUTEX (graph_lock);struct ftrace_hash __rcu *ftrace_graph_hash =EMPTY_HASH ; -struct ftrace_hash *ftrace_graph_notrace_hash =EMPTY_HASH ; +struct ftrace_hash __rcu *ftrace_graph_notrace_hash =EMPTY_HASH ;enum graph_filter_type {GRAPH_FILTER_NOTRACE =0 ,
kernel/trace/trace.h +6 -2
@@ -869,7 +869,7 @@ extern void __trace_graph_return(struct trace_array *tr,#ifdef CONFIG_DYNAMIC_FTRACE extern struct ftrace_hash __rcu *ftrace_graph_hash; -extern struct ftrace_hash *ftrace_graph_notrace_hash; +extern struct ftrace_hash __rcu *ftrace_graph_notrace_hash;static inline int ftrace_graph_addr (struct ftrace_graph_ent *trace) {
@@ -922,10 +922,14 @@ static inline void ftrace_graph_addr_finish(struct ftrace_graph_ret *trace)static inline int ftrace_graph_notrace_addr (unsigned long addr) {int ret =0 ; +struct ftrace_hash *notrace_hash;preempt_disable_notrace (); -if (ftrace_lookup_ip (ftrace_graph_notrace_hash, addr)) + notrace_hash =rcu_dereference_protected (ftrace_graph_notrace_hash, + !preemptible ()); + +if (ftrace_lookup_ip (notrace_hash, addr)) ret =1 ;preempt_enable_notrace ();
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 44/173 ubifs: dont trigger assertion on invalid no-key filename
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
[ Upstream commit f0d07a98a070bb5e443df19c3aa55693cbca9341 ]
If userspace provides an invalid fscrypt no-key filename which encodes a hash value with any of the UBIFS node type bits set (i.e. the high 3 bits), gracefully report ENOENT rather than triggering ubifs_assert().
Test case with kvm-xfstests shell:
. fs/ubifs/config
. ~/xfstests/common/encrypt dev=$(__blkdev_to_ubi_volume /dev/vdc) ubiupdatevol $dev -t
mount $dev /mnt -t ubifs
mkdir /mnt/edir
xfs_io -c set_encpolicy /mnt/edir
rm /mnt/edir/_,,,,,DAAAAAAAAAAAAAAAAAAAAAAAAAA
With the bug, the following assertion fails on the 'rm' command:
[ 19.066048] UBIFS error (ubi0:0 pid 379): ubifs_assert_failed: UBIFS assert failed: !(hash & ~UBIFS_S_KEY_HASH_MASK), in fs/ubifs/key.h:170
--- fs/ubifs/dir.c | 2 ++ 1 file changed, 2 insertions(+)
fs/ubifs/dir.c +2 -0
@@ -253,6 +253,8 @@ static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry,if (nm.hash) {ubifs_assert (fname_len (&nm) ==0 );ubifs_assert (fname_name (&nm) ==NULL ); +if (nm.hash & ~UBIFS_S_KEY_HASH_MASK ) + goto done;/* ENOENT */ dent_key_init_hash (c, &key, dir->i_ino, nm.hash); err =ubifs_tnc_lookup_dh (c, &key, dent, nm.minor_hash); }else {
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 16/173 rxrpc: Fix insufficient receive notification generation
In reply to Greg Kroah-HartmanFrom: David Howells <[email protected]>
[ Upstream commit f71dbf2fb28489a79bde0dca1c8adfb9cdb20a6b ]
In rxrpc_input_data(), rxrpc_notify_socket() is called if the base sequence number of the packet is immediately following the hard-ack point at the end of the function. However, this isn't sufficient, since the recvmsg side may have been advancing the window and then overrun the position in which we're adding - at which point rx_hard_ack >= seq0 and no notification is generated.
Fix this by always generating a notification at the end of the input function.
Without this, a long call may stall, possibly indefinitely.
--- net/rxrpc/input.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
net/rxrpc/input.c +1 -2
@@ -585,8 +585,7 @@ ack: immediate_ack, true, rxrpc_propose_ack_input_data); -if (sp->hdr.seq ==READ_ONCE (call->rx_hard_ack) +1 ) -rxrpc_notify_socket (call); +rxrpc_notify_socket (call);_leave (" [queued]" ); }
Greg Kroah-Hartman
maintainerPATCH 164/173 crypto: artpec6 - return correct error code for failed setkey()
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
commit b828f905904cd76424230c69741a4cabb0174168 upstream.
->setkey() is supposed to retun -EINVAL for invalid key lengths, not -1.
--- drivers/crypto/axis/artpec6_crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/crypto/axis/artpec6_crypto.c +1 -1
@@ -1256,7 +1256,7 @@ static int artpec6_crypto_aead_set_key(sif (len !=16 && len !=24 && len !=32 ) {crypto_aead_set_flags (tfm,CRYPTO_TFM_RES_BAD_KEY_LEN ); -return -1 ; +return -EINVAL ; } ctx->key_length = len;
Greg Kroah-Hartman
maintainerPATCH 171/173 mwifiex: Fix possible buffer overflows in mwifiex_cmd_append_vsie_tlv()
In reply to Greg Kroah-HartmanFrom: Qing Xu <[email protected]>
[ Upstream commit b70261a288ea4d2f4ac7cd04be08a9f0f2de4f4d ]
mwifiex_cmd_append_vsie_tlv() calls memcpy() without checking the destination size may trigger a buffer overflower, which a local user could use to cause denial of service or the execution of arbitrary code.
Fix it by putting the length check before calling memcpy().
--- drivers/net/wireless/marvell/mwifiex/scan.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/net/wireless/marvell/mwifiex/scan.c +7 -0
@@ -2890,6 +2890,13 @@ mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, vs_param_set->header.len =cpu_to_le16 ((((u16 ) priv->vs_ie[id].ie[1 ]) &0x00FF ) +2 ); +if (le16_to_cpu (vs_param_set->header.len) > +MWIFIEX_MAX_VSIE_LEN ) { +mwifiex_dbg (priv->adapter,ERROR , +"Invalid param length!\n" ); +break ; + } +memcpy (vs_param_set->ie, priv->vs_ie[id].ie,le16_to_cpu (vs_param_set->header.len)); *buffer += le16_to_cpu(vs_param_set->header.len) +
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 168/173 scsi: megaraid_sas: Do not initiate OCR if controller is not in ready state
In reply to Greg Kroah-HartmanFrom: Anand Lodnoor <[email protected]>
commit 6d7537270e3283b92f9b327da9d58a4de40fe8d0 upstream.
Driver initiates OCR if a DCMD command times out. But there is a deadlock if the driver attempts to invoke another OCR before the mutex lock (reset_mutex) is released from the previous session of OCR.
This patch takes care of the above scenario using new flag MEGASAS_FUSION_OCR_NOT_POSSIBLE to indicate if OCR is possible.
--- drivers/scsi/megaraid/megaraid_sas_base.c | 3 ++- drivers/scsi/megaraid/megaraid_sas_fusion.c | 3 ++- drivers/scsi/megaraid/megaraid_sas_fusion.h | 1 + 3 files changed, 5 insertions(+), 2 deletions(-)
drivers/scsi/megaraid/megaraid_sas_base.c +2 -1
@@ -4109,7 +4109,8 @@ dcmd_timeout_ocr_possible(struct megasasif (instance->adapter_type ==MFI_SERIES )return KILL_ADAPTER ;else if (instance->unload || -test_bit (MEGASAS_FUSION_IN_RESET , &instance->reset_flags)) +test_bit (MEGASAS_FUSION_OCR_NOT_POSSIBLE , + &instance->reset_flags))return IGNORE_TIMEOUT ;else return INITIATE_OCR ;
drivers/scsi/megaraid/megaraid_sas_fusion.c +2 -1
@@ -4212,6 +4212,7 @@ int megasas_reset_fusion(struct Scsi_Hosif (instance->requestorId && !instance->skip_heartbeat_timer_del)del_timer_sync (&instance->sriov_heartbeat_timer);set_bit (MEGASAS_FUSION_IN_RESET , &instance->reset_flags); +set_bit (MEGASAS_FUSION_OCR_NOT_POSSIBLE , &instance->reset_flags);atomic_set (&instance->adprecovery,MEGASAS_ADPRESET_SM_POLLING ); instance->instancet->disable_intr (instance);megasas_sync_irqs ((unsigned long )instance);
@@ -4399,7 +4400,7 @@ fail_kill_adapter:atomic_set (&instance->adprecovery,MEGASAS_HBA_OPERATIONAL ); } out: -clear_bit (MEGASAS_FUSION_IN_RESET , &instance->reset_flags); +clear_bit (MEGASAS_FUSION_OCR_NOT_POSSIBLE , &instance->reset_flags);mutex_unlock (&instance->reset_mutex);return retval; }
drivers/scsi/megaraid/megaraid_sas_fusion.h +1 -0
@@ -100,6 +100,7 @@ enum MR_RAID_FLAGS_IO_SUB_TYPE {#define MEGASAS_FP_CMD_LEN 16#define MEGASAS_FUSION_IN_RESET 0 +#define MEGASAS_FUSION_OCR_NOT_POSSIBLE 1#define THRESHOLD_REPLY_COUNT 50#define RAID_1_PEER_CMDS 2#define JBOD_MAPS_COUNT 2
Greg Kroah-Hartman
maintainerPATCH 170/173 mwifiex: Fix possible buffer overflows in mwifiex_ret_wmm_get_status()
In reply to Greg Kroah-HartmanFrom: Qing Xu <[email protected]>
[ Upstream commit 3a9b153c5591548612c3955c9600a98150c81875 ]
mwifiex_ret_wmm_get_status() calls memcpy() without checking the destination size.Since the source is given from remote AP which contains illegal wmm elements , this may trigger a heap buffer overflow.
Fix it by putting the length check before calling memcpy().
--- drivers/net/wireless/marvell/mwifiex/wmm.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/wireless/marvell/mwifiex/wmm.c +4 -0
@@ -976,6 +976,10 @@ int mwifiex_ret_wmm_get_status(struct mwifiex_private *priv,"WMM Parameter Set Count: %d\n" , wmm_param_ie->qos_info_bitmap & mask); +if (wmm_param_ie->vend_hdr.len +2 > +sizeof (struct ieee_types_wmm_parameter )) +break ; +memcpy ((u8 *) &priv->curr_bss_params.bss_descriptor. wmm_ie, wmm_param_ie, wmm_param_ie->vend_hdr.len +2 );
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 167/173 pinctrl: sh-pfc: r8a7778: Fix duplicate SDSELF_B and SD1_CLK_B
In reply to Greg Kroah-HartmanFrom: Geert Uytterhoeven <[email protected]>
commit 805f635703b2562b5ddd822c62fc9124087e5dd5 upstream.
The FN_SDSELF_B and FN_SD1_CLK_B enum IDs are used twice, which means one set of users must be wrong. Replace them by the correct enum IDs.
--- drivers/pinctrl/sh-pfc/pfc-r8a7778.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/pinctrl/sh-pfc/pfc-r8a7778.c +2 -2
@@ -2325,7 +2325,7 @@ static const struct pinmux_cfg_reg pinmuFN_ATAG0_A ,0 ,FN_REMOCON_B ,0 ,/* IP0_11_8 [4] */ FN_SD1_DAT2_A ,FN_MMC_D2 ,0 ,FN_BS , -FN_ATADIR0_A ,0 ,FN_SDSELF_B ,0 , +FN_ATADIR0_A ,0 ,FN_SDSELF_A ,0 ,FN_PWM4_B ,0 ,0 ,0 ,0 ,0 ,0 ,0 , /* IP0_7_5 [3] */
@@ -2367,7 +2367,7 @@ static const struct pinmux_cfg_reg pinmuFN_TS_SDAT0_A ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,/* IP1_10_8 [3] */ -FN_SD1_CLK_B ,FN_MMC_D6 ,0 ,FN_A24 , +FN_SD1_CD_A ,FN_MMC_D6 ,0 ,FN_A24 ,FN_DREQ1_A ,0 ,FN_HRX0_B ,FN_TS_SPSYNC0_A ,/* IP1_7_5 [3] */ FN_A23, FN_HTX0_B, FN_TX2_B, FN_DACK2_A,
Greg Kroah-Hartman
maintainerPATCH 144/173 scsi: ufs: Fix ufshcd_probe_hba() reture value in case ufshcd_scsi_add_wlus() fails
In reply to Greg Kroah-HartmanFrom: Bean Huo <[email protected]>
commit b9fc5320212efdfb4e08b825aaa007815fd11d16 upstream.
A non-zero error value likely being returned by ufshcd_scsi_add_wlus() in case of failure of adding the WLs, but ufshcd_probe_hba() doesn't use this value, and doesn't report this failure to upper caller. This patch is to fix this issue.
--- drivers/scsi/ufs/ufshcd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/scsi/ufs/ufshcd.c +2 -1
@@ -6415,7 +6415,8 @@ static int ufshcd_probe_hba(struct ufs_hufshcd_init_icc_levels (hba);/* Add required well known logical units to scsi mid layer */ -if (ufshcd_scsi_add_wlus (hba)) + ret =ufshcd_scsi_add_wlus (hba); +if (ret) goto out;/* Initialize devfreq after UFS device is detected */
Greg Kroah-Hartman
maintainerPATCH 153/173 ARC: [plat-axs10x]: Add missing multicast filter number to GMAC node
In reply to Greg Kroah-HartmanFrom: Jose Abreu <[email protected]>
commit 7980dff398f86a618f502378fa27cf7e77449afa upstream.
Add a missing property to GMAC node so that multicast filtering works correctly.
--- arch/arc/boot/dts/axs10x_mb.dtsi | 1 + 1 file changed, 1 insertion(+)
arch/arc/boot/dts/axs10x_mb.dtsi +1 -0
@@ -70,6 +70,7 @@ interrupt-names = "macirq"; phy-mode = "rgmii"; snps,pbl = < 32 >; + snps,multicast-filter-bins = <256>; clocks = <&apbclk>; clock-names = "stmmaceth"; max-speed = <100>;
Greg Kroah-Hartman
maintainerPATCH 151/173 rtc: hym8563: Return -EINVAL if the time is known to be invalid
In reply to Greg Kroah-HartmanFrom: Paul Kocialkowski <[email protected]>
commit f236a2a2ebabad0848ad0995af7ad1dc7029e895 upstream.
The current code returns -EPERM when the voltage loss bit is set. Since the bit indicates that the time value is not valid, return -EINVAL instead, which is the appropriate error code for this situation.
--- drivers/rtc/rtc-hym8563.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/rtc/rtc-hym8563.c +1 -1
@@ -105,7 +105,7 @@ static int hym8563_rtc_read_time(structif (!hym8563->valid) {dev_warn (&client->dev,"no valid clock/calendar values available\n" ); -return -EPERM ; +return -EINVAL ; } ret =i2c_smbus_read_i2c_block_data (client,HYM8563_SEC ,7 , buf);
Greg Kroah-Hartman
maintainerPATCH 149/173 NFSv4: try lease recovery on NFS4ERR_EXPIRED
In reply to Greg Kroah-HartmanFrom: Robert Milkowski <[email protected]>
commit 924491f2e476f7234d722b24171a4daff61bbe13 upstream.
Currently, if an nfs server returns NFS4ERR_EXPIRED to open(), we return EIO to applications without even trying to recover.
--- fs/nfs/nfs4proc.c | 5 +++++ 1 file changed, 5 insertions(+)
fs/nfs/nfs4proc.c +5 -0
@@ -2923,6 +2923,11 @@ static struct nfs4_state *nfs4_do_open(s exception.retry =1 ;continue ; } +if (status == -NFS4ERR_EXPIRED ) { +nfs4_schedule_lease_recovery (server->nfs_client); + exception.retry =1 ; +continue ; + }if (status == -EAGAIN ) {/* We must have found a delegation */ exception.retry =1 ;
Greg Kroah-Hartman
maintainerPATCH 148/173 NFS/pnfs: Fix pnfs_generic_prepare_to_resend_writes()
In reply to Greg Kroah-HartmanFrom: Trond Myklebust <[email protected]>
commit 221203ce6406273cf00e5c6397257d986c003ee6 upstream.
Instead of making assumptions about the commit verifier contents, change the commit code to ensure we always check that the verifier was set by the XDR code.
--- fs/nfs/direct.c | 4 ++-- fs/nfs/nfs3xdr.c | 5 ++++- fs/nfs/nfs4xdr.c | 5 ++++- fs/nfs/pnfs_nfs.c | 7 +++---- fs/nfs/write.c | 4 +++- 5 files changed, 16 insertions(+), 9 deletions(-)
fs/nfs/direct.c +2 -2
@@ -261,10 +261,10 @@ static int nfs_direct_cmp_commit_data_ve data->ds_commit_index);/* verifier not set so always fail */ -if (verfp->committed <0 ) +if (verfp->committed <0 || data->res.verf->committed <=NFS_UNSTABLE )return 1 ; -return nfs_direct_cmp_verf (verfp, &data->verf); +return nfs_direct_cmp_verf (verfp, data->res.verf); }/**
fs/nfs/nfs3xdr.c +4 -1
@@ -2373,6 +2373,7 @@ static int nfs3_xdr_dec_commit3res(struc void *data) {struct nfs_commitres *result = data; +struct nfs_writeverf *verf = result->verf;enum nfs_stat status;int error;
@@ -2385,7 +2386,9 @@ static int nfs3_xdr_dec_commit3res(struc result->op_status = status;if (status !=NFS3_OK ) goto out_status; - error =decode_writeverf3 (xdr, &result->verf->verifier); + error =decode_writeverf3 (xdr, &verf->verifier); +if (!error) + verf->committed =NFS_FILE_SYNC ; out:return error; out_status:
fs/nfs/nfs4xdr.c +4 -1
@@ -4409,11 +4409,14 @@ static int decode_write_verifier(structstatic int decode_commit (struct xdr_stream *xdr,struct nfs_commitres *res) { +struct nfs_writeverf *verf = res->verf;int status; status =decode_op_hdr (xdr,OP_COMMIT );if (!status) - status =decode_write_verifier (xdr, &res->verf->verifier); + status =decode_write_verifier (xdr, &verf->verifier); +if (!status) + verf->committed =NFS_FILE_SYNC ;return status; }
fs/nfs/pnfs_nfs.c +3 -4
@@ -30,12 +30,11 @@ EXPORT_SYMBOL_GPL(pnfs_generic_rw_releas/* Fake up some data that will cause nfs_commit_release to retry the writes. */ void pnfs_generic_prepare_to_resend_writes (struct nfs_commit_data *data) { -struct nfs_page *first =nfs_list_entry (data->pages.next); +struct nfs_writeverf *verf = data->res.verf; data->task.tk_status =0 ; -memcpy (&data->verf.verifier, &first->wb_verf, -sizeof (data->verf.verifier)); - data->verf.verifier.data[0 ]++;/* ensure verifier mismatch */ +memset (&verf->verifier,0 ,sizeof (verf->verifier)); + verf->committed =NFS_UNSTABLE ; }EXPORT_SYMBOL_GPL (pnfs_generic_prepare_to_resend_writes);
fs/nfs/write.c +3 -1
@@ -1807,6 +1807,7 @@ static void nfs_commit_done(struct rpc_tstatic void nfs_commit_release_pages (struct nfs_commit_data *data) { +const struct nfs_writeverf *verf = data->res.verf;struct nfs_page *req;int status = data->task.tk_status;struct nfs_commit_info cinfo;
@@ -1833,7 +1834,8 @@ static void nfs_commit_release_pages(str/* Okay, COMMIT succeeded, apparently. Check the verifier * returned by the server against all stored verfs. */ -if (!nfs_write_verifier_cmp (&req->wb_verf, &data->verf.verifier)) { +if (verf->committed >NFS_UNSTABLE && + !nfs_write_verifier_cmp (&req->wb_verf, &verf->verifier)) {/* We have a match */ if (req->wb_page)nfs_inode_remove_request (req);
Greg Kroah-Hartman
maintainerPATCH 147/173 nfs: NFS_SWAP should depend on SWAP
In reply to Greg Kroah-HartmanFrom: Geert Uytterhoeven <[email protected]>
commit 474c4f306eefbb21b67ebd1de802d005c7d7ecdc upstream.
If CONFIG_SWAP=n, it does not make much sense to offer the user the option to enable support for swapping over NFS, as that will still fail at run time:
# swapon /swap
swapon: /swap: swapon failed: Function not implementedFix this by adding a dependency on CONFIG_SWAP.
--- fs/nfs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/nfs/Kconfig +1 -1
@@ -89,7 +89,7 @@ config NFS_V4 config NFS_SWAP bool "Provide swap over NFS support" default n - depends on NFS_FS + depends on NFS_FS && SWAP select SUNRPC_SWAP help This option enables swapon to work on files located on NFS mounts.
Greg Kroah-Hartman
maintainerPATCH 163/173 KVM: arm/arm64: Fix young bit from mmu notifier
In reply to Greg Kroah-HartmanFrom: Gavin Shan <[email protected]>
commit cf2d23e0bac9f6b5cd1cba8898f5f05ead40e530 upstream.
kvm_test_age_hva() is called upon mmu_notifier_test_young(), but wrong address range has been passed to handle_hva_to_gpa(). With the wrong address range, no young bits will be checked in handle_hva_to_gpa(). It means zero is always returned from mmu_notifier_test_young().
This fixes the issue by passing correct address range to the underly function handle_hva_to_gpa(), so that the hardware young (access) bit will be visited.
--- virt/kvm/arm/mmu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
virt/kvm/arm/mmu.c +2 -1
@@ -1736,7 +1736,8 @@ int kvm_test_age_hva(struct kvm *kvm, unif (!kvm->arch.pgd)return 0 ;trace_kvm_test_age_hva (hva); -return handle_hva_to_gpa (kvm, hva, hva, kvm_test_age_hva_handler,NULL ); +return handle_hva_to_gpa (kvm, hva, hva +PAGE_SIZE , + kvm_test_age_hva_handler,NULL ); }void kvm_mmu_free_memory_caches (struct kvm_vcpu *vcpu)
Greg Kroah-Hartman
maintainerPATCH 162/173 arm64: cpufeature: Fix the type of no FP/SIMD capability
In reply to Greg Kroah-HartmanFrom: Suzuki K Poulose <[email protected]>
commit 449443c03d8cfdacf7313e17779a2594ebf87e6d upstream.
The NO_FPSIMD capability is defined with scope SYSTEM, which implies that the "absence" of FP/SIMD on at least one CPU is detected only after all the SMP CPUs are brought up. However, we use the status of this capability for every context switch. So, let us change the scope to LOCAL_CPU to allow the detection of this capability as and when the first CPU without FP is brought up.
Also, the current type allows hotplugged CPU to be brought up without FP/SIMD when all the current CPUs have FP/SIMD and we have the userspace up. Fix both of these issues by changing the capability to BOOT_RESTRICTED_LOCAL_CPU_FEATURE.
--- arch/arm64/kernel/cpufeature.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/kernel/cpufeature.c +1 -1
@@ -1103,7 +1103,7 @@ static const struct arm64_cpu_capabiliti {/* FP/SIMD is not implemented */ .capability = ARM64_HAS_NO_FPSIMD, - .type = ARM64_CPUCAP_SYSTEM_FEATURE, + .type = ARM64_CPUCAP_BOOT_RESTRICTED_CPU_LOCAL_FEATURE, .min_field_value = 0, .matches = has_no_fpsimd, },
Greg Kroah-Hartman
maintainerPATCH 161/173 ARM: 8949/1: mm: mark free_memmap as __init
In reply to Greg Kroah-HartmanFrom: Olof Johansson <[email protected]>
commit 31f3010e60522ede237fb145a63b4af5a41718c2 upstream.
As of commit ac7c3e4ff401 ("compiler: enable CONFIG_OPTIMIZE_INLINING forcibly"), free_memmap() might not always be inlined, and thus is triggering a section warning:
WARNING: vmlinux.o(.text.unlikely+0x904): Section mismatch in reference from the function free_memmap() to the function .meminit.text:memblock_free()
Mark it as __init, since the faller (free_unused_memmap) already is.
--- arch/arm/mm/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm/mm/init.c +1 -1
@@ -356,7 +356,7 @@ static inline void poison_init_mem(void *p++ =0xe7fddef0 ; } -static inline void +static inline void __init free_memmap (unsigned long start_pfn,unsigned long end_pfn) {struct page *start_pg, *end_pg;
Greg Kroah-Hartman
maintainerPATCH 159/173 powerpc/pseries: Allow not having ibm, hypertas-functions::hcall-multi-tce for DDW
In reply to Greg Kroah-HartmanFrom: Alexey Kardashevskiy <[email protected]>
commit 7559d3d295f3365ea7ac0c0274c05e633fe4f594 upstream.
By default a pseries guest supports a H_PUT_TCE hypercall which maps a single IOMMU page in a DMA window. Additionally the hypervisor may support H_PUT_TCE_INDIRECT/H_STUFF_TCE which update multiple TCEs at once; this is advertised via the device tree /rtas/ibm,hypertas-functions property which Linux converts to FW_FEATURE_MULTITCE.
FW_FEATURE_MULTITCE is checked when dma_iommu_ops is used; however the code managing the huge DMA window (DDW) ignores it and calls H_PUT_TCE_INDIRECT even if it is explicitly disabled via the "multitce=off" kernel command line parameter.
This adds FW_FEATURE_MULTITCE checking to the DDW code path.
This changes tce_build_pSeriesLP to take liobn and page size as the huge window does not have iommu_table descriptor which usually the place to store these numbers.
--- arch/powerpc/platforms/pseries/iommu.c | 43 ++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 14 deletions(-)
arch/powerpc/platforms/pseries/iommu.c +29 -14
@@ -168,10 +168,10 @@ static unsigned long tce_get_pseries(strreturn be64_to_cpu (*tcep); } -static void tce_free_pSeriesLP (struct iommu_table *,long ,long ); +static void tce_free_pSeriesLP (unsigned long liobn,long ,long );static void tce_freemulti_pSeriesLP (struct iommu_table *,long ,long ); -static int tce_build_pSeriesLP (struct iommu_table *tbl,long tcenum, +static int tce_build_pSeriesLP (unsigned long liobn,long tcenum,long tceshift,long npages,unsigned long uaddr,enum dma_data_direction direction,unsigned long attrs)
@@ -182,25 +182,25 @@ static int tce_build_pSeriesLP(struct ioint ret =0 ;long tcenum_start = tcenum, npages_start = npages; - rpn =__pa (uaddr) >>TCE_SHIFT ; + rpn =__pa (uaddr) >> tceshift; proto_tce =TCE_PCI_READ ;if (direction !=DMA_TO_DEVICE ) proto_tce |=TCE_PCI_WRITE ;while (npages--) { - tce = proto_tce | (rpn &TCE_RPN_MASK ) <<TCE_RPN_SHIFT ; - rc =plpar_tce_put ((u64 )tbl->it_index, (u64 )tcenum <<12 , tce); + tce = proto_tce | (rpn &TCE_RPN_MASK ) << tceshift; + rc =plpar_tce_put ((u64 )liobn, (u64 )tcenum << tceshift, tce);if (unlikely (rc ==H_NOT_ENOUGH_RESOURCES )) { ret = (int )rc; -tce_free_pSeriesLP (tbl, tcenum_start, +tce_free_pSeriesLP (liobn, tcenum_start, (npages_start - (npages +1 )));break ; }if (rc &&printk_ratelimit ()) {printk ("tce_build_pSeriesLP: plpar_tce_put failed. rc=%lld\n" , rc); -printk ("\tindex = 0x%llx\n" , (u64 )tbl->it_index); +printk ("\tindex = 0x%llx\n" , (u64 )liobn);printk ("\ttcenum = 0x%llx\n" , (u64 )tcenum);printk ("\ttce val = 0x%llx\n" , tce );dump_stack ();
@@ -229,7 +229,8 @@ static int tce_buildmulti_pSeriesLP(struunsigned long flags;if ((npages ==1 ) || !firmware_has_feature (FW_FEATURE_MULTITCE )) { -return tce_build_pSeriesLP (tbl, tcenum, npages, uaddr, +return tce_build_pSeriesLP (tbl->it_index, tcenum, + tbl->it_page_shift, npages, uaddr, direction, attrs); }
@@ -245,8 +246,9 @@ static int tce_buildmulti_pSeriesLP(stru/* If allocation fails, fall back to the loop implementation */ if (!tcep) {local_irq_restore (flags); -return tce_build_pSeriesLP (tbl, tcenum, npages, uaddr, - direction, attrs); +return tce_build_pSeriesLP (tbl->it_index, tcenum, + tbl->it_page_shift, + npages, uaddr, direction, attrs); }__this_cpu_write (tce_page, tcep); }
@@ -297,16 +299,16 @@ static int tce_buildmulti_pSeriesLP(strureturn ret; } -static void tce_free_pSeriesLP (struct iommu_table *tbl,long tcenum,long npages) +static void tce_free_pSeriesLP (unsigned long liobn,long tcenum,long npages) {u64 rc;while (npages--) { - rc =plpar_tce_put ((u64 )tbl->it_index, (u64 )tcenum <<12 ,0 ); + rc =plpar_tce_put ((u64 )liobn, (u64 )tcenum <<12 ,0 );if (rc &&printk_ratelimit ()) {printk ("tce_free_pSeriesLP: plpar_tce_put failed. rc=%lld\n" , rc); -printk ("\tindex = 0x%llx\n" , (u64 )tbl->it_index); +printk ("\tindex = 0x%llx\n" , (u64 )liobn);printk ("\ttcenum = 0x%llx\n" , (u64 )tcenum);dump_stack (); }
@@ -321,7 +323,7 @@ static void tce_freemulti_pSeriesLP(struu64 rc;if (!firmware_has_feature (FW_FEATURE_MULTITCE )) -return tce_free_pSeriesLP (tbl, tcenum, npages); +return tce_free_pSeriesLP (tbl->it_index, tcenum, npages); rc =plpar_tce_stuff ((u64 )tbl->it_index, (u64 )tcenum <<12 ,0 , npages);
@@ -436,6 +438,19 @@ static int tce_setrange_multi_pSeriesLP(u64 rc =0 ;long l, limit; +if (!firmware_has_feature (FW_FEATURE_MULTITCE )) { +unsigned long tceshift =be32_to_cpu (maprange->tce_shift); +unsigned long dmastart = (start_pfn <<PAGE_SHIFT ) + +be64_to_cpu (maprange->dma_base); +unsigned long tcenum = dmastart >> tceshift; +unsigned long npages = num_pfn <<PAGE_SHIFT >> tceshift; +void *uaddr =__va (start_pfn <<PAGE_SHIFT ); + +return tce_build_pSeriesLP (be32_to_cpu (maprange->liobn), + tcenum, tceshift, npages, (unsigned long ) uaddr, +DMA_BIDIRECTIONAL ,0 ); + } +local_irq_disable ();/* to protect tcep and the page behind it */ tcep =__this_cpu_read (tce_page);
Greg Kroah-Hartman
maintainerPATCH 158/173 powerpc/pseries/vio: Fix iommu_table use-after-free refcount warning
In reply to Greg Kroah-HartmanFrom: Tyrel Datwyler <[email protected]>
commit aff8c8242bc638ba57247ae1ec5f272ac3ed3b92 upstream.
Commit e5afdf9dd515 ("powerpc/vfio_spapr_tce: Add reference counting to iommu_table") missed an iommu_table allocation in the pseries vio code. The iommu_table is allocated with kzalloc and as a result the associated kref gets a value of zero. This has the side effect that during a DLPAR remove of the associated virtual IOA the iommu_tce_table_put() triggers a use-after-free underflow warning.
Call Trace: [c0000002879e39f0] [c00000000071ecb4] refcount_warn_saturate+0x184/0x190
(unreliable)
[c0000002879e3a50] [c0000000000500ac] iommu_tce_table_put+0x9c/0xb0 [c0000002879e3a70] [c0000000000f54e4] vio_dev_release+0x34/0x70 [c0000002879e3aa0] [c00000000087cfa4] device_release+0x54/0xf0 [c0000002879e3b10] [c000000000d64c84] kobject_cleanup+0xa4/0x240 [c0000002879e3b90] [c00000000087d358] put_device+0x28/0x40 [c0000002879e3bb0] [c0000000007a328c] dlpar_remove_slot+0x15c/0x250 [c0000002879e3c50] [c0000000007a348c] remove_slot_store+0xac/0xf0 [c0000002879e3cd0] [c000000000d64220] kobj_attr_store+0x30/0x60 [c0000002879e3cf0] [c0000000004ff13c] sysfs_kf_write+0x6c/0xa0 [c0000002879e3d10] [c0000000004fde4c] kernfs_fop_write+0x18c/0x260 [c0000002879e3d60] [c000000000410f3c] __vfs_write+0x3c/0x70 [c0000002879e3d80] [c000000000415408] vfs_write+0xc8/0x250 [c0000002879e3dd0] [c0000000004157dc] ksys_write+0x7c/0x120 [c0000002879e3e20] [c00000000000b278] system_call+0x5c/0x68
Further, since the refcount was always zero the iommu_tce_table_put() fails to call the iommu_table release function resulting in a leak.
Fix this issue be initilizing the iommu_table kref immediately after allocation.
--- arch/powerpc/platforms/pseries/vio.c | 2 ++ 1 file changed, 2 insertions(+)
arch/powerpc/platforms/pseries/vio.c +2 -0
@@ -1195,6 +1195,8 @@ static struct iommu_table *vio_build_iomif (tbl ==NULL )return NULL ; +kref_init (&tbl->it_kref); +of_parse_dma_window (dev->dev.of_node, dma_window, &tbl->it_index, &offset, &size);
Greg Kroah-Hartman
maintainerPATCH 132/173 KVM: VMX: Add non-canonical check on writes to RTIT address MSRs
In reply to Greg Kroah-HartmanFrom: Sean Christopherson <[email protected]>
[ Upstream commit fe6ed369fca98e99df55c932b85782a5687526b5 ]
Reject writes to RTIT address MSRs if the data being written is a non-canonical address as the MSRs are subject to canonical checks, e.g. KVM will trigger an unchecked #GP when loading the values to hardware during pt_guest_enter().
--- arch/x86/kvm/vmx/vmx.c | 8033 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 8033 insertions(+) create mode 100644 arch/x86/kvm/vmx/vmx.c
arch/x86/kvm/vmx/vmx.c new file +8033 -0
@@ -0,0 +1,8033 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* +* Kernel-based Virtual Machine driver for Linux +* +* This module enables machines with Intel VT-x extensions to run virtual +* machines without emulation or binary translation. +* +* Copyright (C) 2006 Qumranet, Inc. +* Copyright 2010 Red Hat, Inc. and/or its affiliates. +* +* Authors: +* Avi Kivity <[email protected]> +* Yaniv Kamay <[email protected]> +*/ + +#include <linux/frame.h> +#include <linux/highmem.h> +#include <linux/hrtimer.h> +#include <linux/kernel.h> +#include <linux/kvm_host.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/mod_devicetable.h> +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/sched/smt.h> +#include <linux/slab.h> +#include <linux/tboot.h> +#include <linux/trace_events.h> + +#include <asm/apic.h> +#include <asm/asm.h> +#include <asm/cpu.h> +#include <asm/debugreg.h> +#include <asm/desc.h> +#include <asm/fpu/internal.h> +#include <asm/io.h> +#include <asm/irq_remapping.h> +#include <asm/kexec.h> +#include <asm/perf_event.h> +#include <asm/mce.h> +#include <asm/mmu_context.h> +#include <asm/mshyperv.h> +#include <asm/spec-ctrl.h> +#include <asm/virtext.h> +#include <asm/vmx.h> + +#include "capabilities.h" +#include "cpuid.h" +#include "evmcs.h" +#include "irq.h" +#include "kvm_cache_regs.h" +#include "lapic.h" +#include "mmu.h" +#include "nested.h" +#include "ops.h" +#include "pmu.h" +#include "trace.h" +#include "vmcs.h" +#include "vmcs12.h" +#include "vmx.h" +#include "x86.h" + +MODULE_AUTHOR ("Qumranet" ); +MODULE_LICENSE ("GPL" ); + +static const struct x86_cpu_id vmx_cpu_id[] = { +X86_FEATURE_MATCH (X86_FEATURE_VMX ), + {} +}; +MODULE_DEVICE_TABLE (x86cpu, vmx_cpu_id); + +bool __read_mostly enable_vpid =1 ; +module_param_named (vpid, enable_vpid, bool,0444 ); + +static bool __read_mostly enable_vnmi =1 ; +module_param_named (vnmi, enable_vnmi, bool,S_IRUGO ); + +bool __read_mostly flexpriority_enabled =1 ; +module_param_named (flexpriority, flexpriority_enabled, bool,S_IRUGO ); + +bool __read_mostly enable_ept =1 ; +module_param_named (ept, enable_ept, bool,S_IRUGO ); + +bool __read_mostly enable_unrestricted_guest =1 ; +module_param_named (unrestricted_guest, + enable_unrestricted_guest, bool,S_IRUGO ); + +bool __read_mostly enable_ept_ad_bits =1 ; +module_param_named (eptad, enable_ept_ad_bits, bool,S_IRUGO ); + +static bool __read_mostly emulate_invalid_guest_state = true; +module_param (emulate_invalid_guest_state, bool,S_IRUGO ); + +static bool __read_mostly fasteoi =1 ; +module_param (fasteoi, bool,S_IRUGO ); + +static bool __read_mostly enable_apicv =1 ; +module_param (enable_apicv, bool,S_IRUGO ); + +/* +* If nested=1, nested virtualization is supported, i.e., guests may use +* VMX and be a hypervisor for its own guests. If nested=0, guests may not +* use VMX instructions. +*/ +static bool __read_mostly nested =1 ; +module_param (nested, bool,S_IRUGO ); + +bool __read_mostly enable_pml =1 ; +module_param_named (pml, enable_pml, bool,S_IRUGO ); + +static bool __read_mostly dump_invalid_vmcs =0 ; +module_param (dump_invalid_vmcs, bool,0644 ); + +#define MSR_BITMAP_MODE_X2APIC 1 +#define MSR_BITMAP_MODE_X2APIC_APICV 2 + +#define KVM_VMX_TSC_MULTIPLIER_MAX 0xffffffffffffffffULL + +/* Guest_tsc -> host_tsc conversion requires 64-bit division. */ +static int __read_mostly cpu_preemption_timer_multi; +static bool __read_mostly enable_preemption_timer =1 ; +#ifdef CONFIG_X86_64 +module_param_named (preemption_timer, enable_preemption_timer, bool,S_IRUGO ); +#endif + +#define KVM_VM_CR0_ALWAYS_OFF (X86_CR0_NW | X86_CR0_CD) +#define KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST X86_CR0_NE +#define KVM_VM_CR0_ALWAYS_ON \ + (KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST | \ + X86_CR0_WP | X86_CR0_PG | X86_CR0_PE) +#define KVM_CR4_GUEST_OWNED_BITS \ + (X86_CR4_PVI | X86_CR4_DE | X86_CR4_PCE | X86_CR4_OSFXSR \ + | X86_CR4_OSXMMEXCPT | X86_CR4_LA57 | X86_CR4_TSD) + +#define KVM_VM_CR4_ALWAYS_ON_UNRESTRICTED_GUEST X86_CR4_VMXE +#define KVM_PMODE_VM_CR4_ALWAYS_ON (X86_CR4_PAE | X86_CR4_VMXE) +#define KVM_RMODE_VM_CR4_ALWAYS_ON (X86_CR4_VME | X86_CR4_PAE | X86_CR4_VMXE) + +#define RMODE_GUEST_OWNED_EFLAGS_BITS (~(X86_EFLAGS_IOPL | X86_EFLAGS_VM)) + +#define MSR_IA32_RTIT_STATUS_MASK (~(RTIT_STATUS_FILTEREN | \ + RTIT_STATUS_CONTEXTEN | RTIT_STATUS_TRIGGEREN | \ + RTIT_STATUS_ERROR | RTIT_STATUS_STOPPED | \ + RTIT_STATUS_BYTECNT)) + +#define MSR_IA32_RTIT_OUTPUT_BASE_MASK \ + (~((1UL << cpuid_query_maxphyaddr(vcpu)) - 1) | 0x7f) + +/* +* These 2 parameters are used to config the controls for Pause-Loop Exiting: +* ple_gap: upper bound on the amount of time between two successive +* executions of PAUSE in a loop. Also indicate if ple enabled. +* According to test, this time is usually smaller than 128 cycles. +* ple_window: upper bound on the amount of time a guest is allowed to execute +* in a PAUSE loop. Tests indicate that most spinlocks are held for +* less than 2^12 cycles +* Time is measured based on a counter that runs at the same rate as the TSC, +* refer SDM volume 3b section 21.6.13 & 22.1.3. +*/ +static unsigned int ple_gap =KVM_DEFAULT_PLE_GAP ; +module_param (ple_gap, uint,0444 ); + +static unsigned int ple_window =KVM_VMX_DEFAULT_PLE_WINDOW ; +module_param (ple_window, uint,0444 ); + +/* Default doubles per-vcpu window every exit. */ +static unsigned int ple_window_grow =KVM_DEFAULT_PLE_WINDOW_GROW ; +module_param (ple_window_grow, uint,0444 ); + +/* Default resets per-vcpu window every exit to ple_window. */ +static unsigned int ple_window_shrink =KVM_DEFAULT_PLE_WINDOW_SHRINK ; +module_param (ple_window_shrink, uint,0444 ); + +/* Default is to compute the maximum so we can never overflow. */ +static unsigned int ple_window_max =KVM_VMX_DEFAULT_PLE_WINDOW_MAX ; +module_param (ple_window_max, uint,0444 ); + +/* Default is SYSTEM mode, 1 for host-guest mode */ +int __read_mostly pt_mode =PT_MODE_SYSTEM ; +module_param (pt_mode, int,S_IRUGO ); + +static DEFINE_STATIC_KEY_FALSE (vmx_l1d_should_flush); +static DEFINE_STATIC_KEY_FALSE (vmx_l1d_flush_cond); +static DEFINE_MUTEX (vmx_l1d_flush_mutex); + +/* Storage for pre module init parameter parsing */ +static enum vmx_l1d_flush_state __read_mostly vmentry_l1d_flush_param =VMENTER_L1D_FLUSH_AUTO ; + +static const struct { +const char *option; +bool for_parse; +} vmentry_l1d_param[] = { + [VMENTER_L1D_FLUSH_AUTO ] = {"auto" , true}, + [VMENTER_L1D_FLUSH_NEVER ] = {"never" , true}, + [VMENTER_L1D_FLUSH_COND ] = {"cond" , true}, + [VMENTER_L1D_FLUSH_ALWAYS ] = {"always" , true}, + [VMENTER_L1D_FLUSH_EPT_DISABLED ] = {"EPT disabled" , false}, + [VMENTER_L1D_FLUSH_NOT_REQUIRED ] = {"not required" , false}, +}; + +#define L1D_CACHE_ORDER 4 +static void *vmx_l1d_flush_pages; + +static int vmx_setup_l1d_flush (enum vmx_l1d_flush_state l1tf) +{ +struct page *page; +unsigned int i; + +if (!boot_cpu_has_bug (X86_BUG_L1TF )) { + l1tf_vmx_mitigation =VMENTER_L1D_FLUSH_NOT_REQUIRED ; +return 0 ; + } + +if (!enable_ept) { + l1tf_vmx_mitigation =VMENTER_L1D_FLUSH_EPT_DISABLED ; +return 0 ; + } + +if (boot_cpu_has (X86_FEATURE_ARCH_CAPABILITIES )) { +u64 msr; + +rdmsrl (MSR_IA32_ARCH_CAPABILITIES , msr); +if (msr &ARCH_CAP_SKIP_VMENTRY_L1DFLUSH ) { + l1tf_vmx_mitigation =VMENTER_L1D_FLUSH_NOT_REQUIRED ; +return 0 ; + } + } + +/* If set to auto use the default l1tf mitigation method */ +if (l1tf ==VMENTER_L1D_FLUSH_AUTO ) { +switch (l1tf_mitigation) { +case L1TF_MITIGATION_OFF : + l1tf =VMENTER_L1D_FLUSH_NEVER ; +break ; +case L1TF_MITIGATION_FLUSH_NOWARN : +case L1TF_MITIGATION_FLUSH : +case L1TF_MITIGATION_FLUSH_NOSMT : + l1tf =VMENTER_L1D_FLUSH_COND ; +break ; +case L1TF_MITIGATION_FULL : +case L1TF_MITIGATION_FULL_FORCE : + l1tf =VMENTER_L1D_FLUSH_ALWAYS ; +break ; + } + }else if (l1tf_mitigation ==L1TF_MITIGATION_FULL_FORCE ) { + l1tf =VMENTER_L1D_FLUSH_ALWAYS ; + } + +if (l1tf !=VMENTER_L1D_FLUSH_NEVER && !vmx_l1d_flush_pages && + !boot_cpu_has (X86_FEATURE_FLUSH_L1D )) { +/* +* This allocation for vmx_l1d_flush_pages is not tied to a VM +* lifetime and so should not be charged to a memcg. +*/ + page =alloc_pages (GFP_KERNEL ,L1D_CACHE_ORDER ); +if (!page) +return -ENOMEM ; + vmx_l1d_flush_pages =page_address (page); + +/* +* Initialize each page with a different pattern in +* order to protect against KSM in the nested +* virtualization case. +*/ +for (i =0 ; i <1u <<L1D_CACHE_ORDER ; ++i) { +memset (vmx_l1d_flush_pages + i *PAGE_SIZE , i +1 , +PAGE_SIZE ); + } + } + + l1tf_vmx_mitigation = l1tf; + +if (l1tf !=VMENTER_L1D_FLUSH_NEVER ) +static_branch_enable (&vmx_l1d_should_flush); +else +static_branch_disable (&vmx_l1d_should_flush); + +if (l1tf ==VMENTER_L1D_FLUSH_COND ) +static_branch_enable (&vmx_l1d_flush_cond); +else +static_branch_disable (&vmx_l1d_flush_cond); +return 0 ; +} + +static int vmentry_l1d_flush_parse (const char *s) +{ +unsigned int i; + +if (s) { +for (i =0 ; i <ARRAY_SIZE (vmentry_l1d_param); i++) { +if (vmentry_l1d_param[i].for_parse && +sysfs_streq (s, vmentry_l1d_param[i].option)) +return i; + } + } +return -EINVAL ; +} + +static int vmentry_l1d_flush_set (const char *s,const struct kernel_param *kp) +{ +int l1tf, ret; + + l1tf =vmentry_l1d_flush_parse (s); +if (l1tf <0 ) +return l1tf; + +if (!boot_cpu_has (X86_BUG_L1TF )) +return 0 ; + +/* +* Has vmx_init() run already? If not then this is the pre init +* parameter parsing. In that case just store the value and let +* vmx_init() do the proper setup after enable_ept has been +* established. +*/ +if (l1tf_vmx_mitigation ==VMENTER_L1D_FLUSH_AUTO ) { + vmentry_l1d_flush_param = l1tf; +return 0 ; + } + +mutex_lock (&vmx_l1d_flush_mutex); + ret =vmx_setup_l1d_flush (l1tf); +mutex_unlock (&vmx_l1d_flush_mutex); +return ret; +} + +static int vmentry_l1d_flush_get (char *s,const struct kernel_param *kp) +{ +if (WARN_ON_ONCE (l1tf_vmx_mitigation >=ARRAY_SIZE (vmentry_l1d_param))) +return sprintf (s,"???\n" ); + +return sprintf (s,"%s\n" , vmentry_l1d_param[l1tf_vmx_mitigation].option); +} + +static const struct kernel_param_ops vmentry_l1d_flush_ops = { + .set = vmentry_l1d_flush_set, + .get = vmentry_l1d_flush_get, +}; +module_param_cb (vmentry_l1d_flush, &vmentry_l1d_flush_ops,NULL ,0644 ); + +static bool guest_state_valid (struct kvm_vcpu *vcpu); +static u32 vmx_segment_access_rights (struct kvm_segment *var); +static __always_inline void vmx_disable_intercept_for_msr(unsigned long *msr_bitmap, +u32 msr,int type); + +void vmx_vmexit (void ); + +#define vmx_insn_failed(fmt...) \ +do { \ + WARN_ONCE(1, fmt); \ + pr_warn_ratelimited(fmt); \ +} while (0) + +asmlinkage void vmread_error(unsigned long field, bool fault) +{ +if (fault) +kvm_spurious_fault (); +else +vmx_insn_failed ("kvm: vmread failed: field=%lx\n" , field); +} + +noinline void vmwrite_error(unsigned long field, unsigned long value) +{ +vmx_insn_failed ("kvm: vmwrite failed: field=%lx val=%lx err=%d\n" , + field, value,vmcs_read32 (VM_INSTRUCTION_ERROR )); +} + +noinline void vmclear_error(struct vmcs *vmcs, u64 phys_addr) +{ +vmx_insn_failed ("kvm: vmclear failed: %p/%llx\n" , vmcs, phys_addr); +} + +noinline void vmptrld_error(struct vmcs *vmcs, u64 phys_addr) +{ +vmx_insn_failed ("kvm: vmptrld failed: %p/%llx\n" , vmcs, phys_addr); +} + +noinline void invvpid_error(unsigned long ext, u16 vpid, gva_t gva) +{ +vmx_insn_failed ("kvm: invvpid failed: ext=0x%lx vpid=%u gva=0x%lx\n" , + ext, vpid, gva); +} + +noinline void invept_error(unsigned long ext, u64 eptp, gpa_t gpa) +{ +vmx_insn_failed ("kvm: invept failed: ext=0x%lx eptp=%llx gpa=0x%llx\n" , + ext, eptp, gpa); +} + +static DEFINE_PER_CPU(struct vmcs *, vmxarea); +DEFINE_PER_CPU (struct vmcs *, current_vmcs); +/* +* We maintain a per-CPU linked-list of VMCS loaded on that CPU. This is needed +* when a CPU is brought down, and we need to VMCLEAR all VMCSs loaded on it. +*/ +static DEFINE_PER_CPU(struct list_head, loaded_vmcss_on_cpu); + +/* +* We maintian a per-CPU linked-list of vCPU, so in wakeup_handler() we +* can find which vCPU should be waken up. +*/ +static DEFINE_PER_CPU(struct list_head, blocked_vcpu_on_cpu); +static DEFINE_PER_CPU(spinlock_t, blocked_vcpu_on_cpu_lock); + +static DECLARE_BITMAP(vmx_vpid_bitmap, VMX_NR_VPIDS); +static DEFINE_SPINLOCK (vmx_vpid_lock); + +struct vmcs_config vmcs_config; +struct vmx_capability vmx_capability; + +#define VMX_SEGMENT_FIELD (seg) \ + [VCPU_SREG_##seg] = { \ + .selector = GUEST_##seg##_SELECTOR, \ + .base = GUEST_##seg##_BASE, \ + .limit = GUEST_##seg##_LIMIT, \ + .ar_bytes = GUEST_##seg##_AR_BYTES, \ + } + +static const struct kvm_vmx_segment_field { +unsigned selector; +unsigned base; +unsigned limit; +unsigned ar_bytes; +} kvm_vmx_segment_fields[] = { +VMX_SEGMENT_FIELD (CS ), +VMX_SEGMENT_FIELD (DS ), +VMX_SEGMENT_FIELD (ES ), +VMX_SEGMENT_FIELD (FS ), +VMX_SEGMENT_FIELD (GS ), +VMX_SEGMENT_FIELD (SS ), +VMX_SEGMENT_FIELD (TR ), +VMX_SEGMENT_FIELD (LDTR ), +}; + +u64 host_efer; +static unsigned long host_idt_base; + +/* +* Though SYSCALL is only supported in 64-bit mode on Intel CPUs, kvm +* will emulate SYSCALL in legacy mode if the vendor string in guest +* CPUID.0:{EBX,ECX,EDX} is "AuthenticAMD" or "AMDisbetter!" To +* support this emulation, IA32_STAR must always be included in +* vmx_msr_index[], even in i386 builds. +*/ +const u32 vmx_msr_index[] = { +#ifdef CONFIG_X86_64 + MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR, +#endif + MSR_EFER, MSR_TSC_AUX, MSR_STAR, + MSR_IA32_TSX_CTRL, +}; + +#if IS_ENABLED(CONFIG_HYPERV) +static bool __read_mostly enlightened_vmcs = true; +module_param(enlightened_vmcs, bool, 0444); + +/* check_ept_pointer() should be under protection of ept_pointer_lock. */ +static void check_ept_pointer_match(struct kvm *kvm) +{ + struct kvm_vcpu *vcpu; + u64 tmp_eptp = INVALID_PAGE; + int i; + + kvm_for_each_vcpu(i, vcpu, kvm) { + if (!VALID_PAGE(tmp_eptp)) { + tmp_eptp = to_vmx(vcpu)->ept_pointer; + } else if (tmp_eptp != to_vmx(vcpu)->ept_pointer) { + to_kvm_vmx(kvm)->ept_pointers_match + = EPT_POINTERS_MISMATCH; + return; + } + } + + to_kvm_vmx(kvm)->ept_pointers_match = EPT_POINTERS_MATCH; +} + +static int kvm_fill_hv_flush_list_func(struct hv_guest_mapping_flush_list *flush, + void *data) +{ + struct kvm_tlb_range *range = data; + + return hyperv_fill_flush_guest_mapping_list(flush, range->start_gfn, + range->pages); +} + +static inline int __hv_remote_flush_tlb_with_range(struct kvm *kvm, + struct kvm_vcpu *vcpu, struct kvm_tlb_range *range) +{ + u64 ept_pointer = to_vmx(vcpu)->ept_pointer; + + /* + * FLUSH_GUEST_PHYSICAL_ADDRESS_SPACE hypercall needs address + * of the base of EPT PML4 table, strip off EPT configuration + * information. + */ + if (range) + return hyperv_flush_guest_mapping_range(ept_pointer & PAGE_MASK, + kvm_fill_hv_flush_list_func, (void *)range); + else + return hyperv_flush_guest_mapping(ept_pointer & PAGE_MASK); +} + +static int hv_remote_flush_tlb_with_range(struct kvm *kvm, + struct kvm_tlb_range *range) +{ + struct kvm_vcpu *vcpu; + int ret = 0, i; + + spin_lock(&to_kvm_vmx(kvm)->ept_pointer_lock); + + if (to_kvm_vmx(kvm)->ept_pointers_match == EPT_POINTERS_CHECK) + check_ept_pointer_match(kvm); + + if (to_kvm_vmx(kvm)->ept_pointers_match != EPT_POINTERS_MATCH) { + kvm_for_each_vcpu(i, vcpu, kvm) { + /* If ept_pointer is invalid pointer, bypass flush request. */ + if (VALID_PAGE(to_vmx(vcpu)->ept_pointer)) + ret |= __hv_remote_flush_tlb_with_range( + kvm, vcpu, range); + } + } else { + ret = __hv_remote_flush_tlb_with_range(kvm, + kvm_get_vcpu(kvm, 0), range); + } + + spin_unlock(&to_kvm_vmx(kvm)->ept_pointer_lock); + return ret; +} +static int hv_remote_flush_tlb(struct kvm *kvm) +{ + return hv_remote_flush_tlb_with_range(kvm, NULL); +} + +static int hv_enable_direct_tlbflush(struct kvm_vcpu *vcpu) +{ + struct hv_enlightened_vmcs *evmcs; + struct hv_partition_assist_pg **p_hv_pa_pg = + &vcpu->kvm->arch.hyperv.hv_pa_pg; + /* + * Synthetic VM-Exit is not enabled in current code and so All + * evmcs in singe VM shares same assist page. + */ + if (!*p_hv_pa_pg) + *p_hv_pa_pg = kzalloc(PAGE_SIZE, GFP_KERNEL); + + if (!*p_hv_pa_pg) + return -ENOMEM; + + evmcs = (struct hv_enlightened_vmcs *)to_vmx(vcpu)->loaded_vmcs->vmcs; + + evmcs->partition_assist_page = + __pa(*p_hv_pa_pg); + evmcs->hv_vm_id = (unsigned long)vcpu->kvm; + evmcs->hv_enlightenments_control.nested_flush_hypercall = 1; + + return 0; +} + +#endif /* IS_ENABLED(CONFIG_HYPERV) */ + +/* + * Comment's format: document - errata name - stepping - processor name. + * Refer from + * https://www.virtualbox.org/svn/vbox/trunk/src/VBox/VMM/VMMR0/HMR0.cpp + */ +static u32 vmx_preemption_cpu_tfms[] = { +/* 323344.pdf - BA86 - D0 - Xeon 7500 Series */ +0x000206E6, +/* 323056.pdf - AAX65 - C2 - Xeon L3406 */ +/* 322814.pdf - AAT59 - C2 - i7-600, i5-500, i5-400 and i3-300 Mobile */ +/* 322911.pdf - AAU65 - C2 - i5-600, i3-500 Desktop and Pentium G6950 */ +0x00020652, +/* 322911.pdf - AAU65 - K0 - i5-600, i3-500 Desktop and Pentium G6950 */ +0x00020655, +/* 322373.pdf - AAO95 - B1 - Xeon 3400 Series */ +/* 322166.pdf - AAN92 - B1 - i7-800 and i5-700 Desktop */ +/* + * 320767.pdf - AAP86 - B1 - + * i7-900 Mobile Extreme, i7-800 and i7-700 Mobile + */ +0x000106E5, +/* 321333.pdf - AAM126 - C0 - Xeon 3500 */ +0x000106A0, +/* 321333.pdf - AAM126 - C1 - Xeon 3500 */ +0x000106A1, +/* 320836.pdf - AAJ124 - C0 - i7-900 Desktop Extreme and i7-900 Desktop */ +0x000106A4, + /* 321333.pdf - AAM126 - D0 - Xeon 3500 */ + /* 321324.pdf - AAK139 - D0 - Xeon 5500 */ + /* 320836.pdf - AAJ124 - D0 - i7-900 Extreme and i7-900 Desktop */ +0x000106A5, + /* Xeon E3-1220 V2 */ +0x000306A8, +}; + +static inline bool cpu_has_broken_vmx_preemption_timer(void) +{ + u32 eax = cpuid_eax(0x00000001), i; + + /* Clear the reserved bits */ + eax &= ~(0x3U << 14 | 0xfU << 28); + for (i = 0; i < ARRAY_SIZE(vmx_preemption_cpu_tfms); i++) + if (eax == vmx_preemption_cpu_tfms[i]) + return true; + + return false; +} + +static inline bool cpu_need_virtualize_apic_accesses(struct kvm_vcpu *vcpu) +{ + return flexpriority_enabled && lapic_in_kernel(vcpu); +} + +static inline bool report_flexpriority(void) +{ + return flexpriority_enabled; +} + +static inline int __find_msr_index(struct vcpu_vmx *vmx, u32 msr) +{ + int i; + + for (i = 0; i < vmx->nmsrs; ++i) + if (vmx_msr_index[vmx->guest_msrs[i].index] == msr) + return i; + return -1; +} + +struct shared_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr) +{ + int i; + + i = __find_msr_index(vmx, msr); + if (i >= 0) + return &vmx->guest_msrs[i]; + return NULL; +} + +static int vmx_set_guest_msr(struct vcpu_vmx *vmx, struct shared_msr_entry *msr, u64 data) +{ + int ret = 0; + + u64 old_msr_data = msr->data; + msr->data = data; + if (msr - vmx->guest_msrs < vmx->save_nmsrs) { + preempt_disable(); + ret = kvm_set_shared_msr(msr->index, msr->data, + msr->mask); + preempt_enable(); + if (ret) + msr->data = old_msr_data; + } + return ret; +} + +void loaded_vmcs_init(struct loaded_vmcs *loaded_vmcs) +{ + vmcs_clear(loaded_vmcs->vmcs); + if (loaded_vmcs->shadow_vmcs && loaded_vmcs->launched) + vmcs_clear(loaded_vmcs->shadow_vmcs); + loaded_vmcs->cpu = -1; + loaded_vmcs->launched = 0; +} + +#ifdef CONFIG_KEXEC_CORE +/* + * This bitmap is used to indicate whether the vmclear + * operation is enabled on all cpus. All disabled by + * default. + */ +static cpumask_t crash_vmclear_enabled_bitmap = CPU_MASK_NONE; + +static inline void crash_enable_local_vmclear(int cpu) +{ + cpumask_set_cpu(cpu, &crash_vmclear_enabled_bitmap); +} + +static inline void crash_disable_local_vmclear(int cpu) +{ + cpumask_clear_cpu(cpu, &crash_vmclear_enabled_bitmap); +} + +static inline int crash_local_vmclear_enabled(int cpu) +{ + return cpumask_test_cpu(cpu, &crash_vmclear_enabled_bitmap); +} + +static void crash_vmclear_local_loaded_vmcss(void) +{ + int cpu = raw_smp_processor_id(); + struct loaded_vmcs *v; + + if (!crash_local_vmclear_enabled(cpu)) + return; + + list_for_each_entry(v, &per_cpu(loaded_vmcss_on_cpu, cpu), + loaded_vmcss_on_cpu_link) + vmcs_clear(v->vmcs); +} +#else +static inline void crash_enable_local_vmclear(int cpu) { } +static inline void crash_disable_local_vmclear(int cpu) { } +#endif /* CONFIG_KEXEC_CORE */ + +static void __loaded_vmcs_clear(void *arg) +{ + struct loaded_vmcs *loaded_vmcs = arg; + int cpu = raw_smp_processor_id(); + + if (loaded_vmcs->cpu != cpu) + return; /* vcpu migration can race with cpu offline */ + if (per_cpu(current_vmcs, cpu) == loaded_vmcs->vmcs) + per_cpu(current_vmcs, cpu) = NULL; + crash_disable_local_vmclear(cpu); + list_del(&loaded_vmcs->loaded_vmcss_on_cpu_link); + + /* + * we should ensure updating loaded_vmcs->loaded_vmcss_on_cpu_link + * is before setting loaded_vmcs->vcpu to -1 which is done in + * loaded_vmcs_init. Otherwise, other cpu can see vcpu = -1 fist + * then adds the vmcs into percpu list before it is deleted. + */ + smp_wmb(); + + loaded_vmcs_init(loaded_vmcs); + crash_enable_local_vmclear(cpu); +} + +void loaded_vmcs_clear(struct loaded_vmcs *loaded_vmcs) +{ + int cpu = loaded_vmcs->cpu; + + if (cpu != -1) + smp_call_function_single(cpu, + __loaded_vmcs_clear, loaded_vmcs, 1); +} + +static bool vmx_segment_cache_test_set(struct vcpu_vmx *vmx, unsigned seg, + unsigned field) +{ + bool ret; + u32 mask = 1 << (seg * SEG_FIELD_NR + field); + + if (!kvm_register_is_available(&vmx->vcpu, VCPU_EXREG_SEGMENTS)) { + kvm_register_mark_available(&vmx->vcpu, VCPU_EXREG_SEGMENTS); + vmx->segment_cache.bitmask = 0; + } + ret = vmx->segment_cache.bitmask & mask; + vmx->segment_cache.bitmask |= mask; + return ret; +} + +static u16 vmx_read_guest_seg_selector(struct vcpu_vmx *vmx, unsigned seg) +{ + u16 *p = &vmx->segment_cache.seg[seg].selector; + + if (!vmx_segment_cache_test_set(vmx, seg, SEG_FIELD_SEL)) + *p = vmcs_read16(kvm_vmx_segment_fields[seg].selector); + return *p; +} + +static ulong vmx_read_guest_seg_base(struct vcpu_vmx *vmx, unsigned seg) +{ + ulong *p = &vmx->segment_cache.seg[seg].base; + + if (!vmx_segment_cache_test_set(vmx, seg, SEG_FIELD_BASE)) + *p = vmcs_readl(kvm_vmx_segment_fields[seg].base); + return *p; +} + +static u32 vmx_read_guest_seg_limit(struct vcpu_vmx *vmx, unsigned seg) +{ + u32 *p = &vmx->segment_cache.seg[seg].limit; + + if (!vmx_segment_cache_test_set(vmx, seg, SEG_FIELD_LIMIT)) + *p = vmcs_read32(kvm_vmx_segment_fields[seg].limit); + return *p; +} + +static u32 vmx_read_guest_seg_ar(struct vcpu_vmx *vmx, unsigned seg) +{ + u32 *p = &vmx->segment_cache.seg[seg].ar; + + if (!vmx_segment_cache_test_set(vmx, seg, SEG_FIELD_AR)) + *p = vmcs_read32(kvm_vmx_segment_fields[seg].ar_bytes); + return *p; +} + +void update_exception_bitmap(struct kvm_vcpu *vcpu) +{ + u32 eb; + + eb = (1u << PF_VECTOR) | (1u << UD_VECTOR) | (1u << MC_VECTOR) | + (1u << DB_VECTOR) | (1u << AC_VECTOR); + /* + * Guest access to VMware backdoor ports could legitimately + * trigger #GP because of TSS I/O permission bitmap. + * We intercept those #GP and allow access to them anyway + * as VMware does. + */ + if (enable_vmware_backdoor) + eb |= (1u << GP_VECTOR); + if ((vcpu->guest_debug & + (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP)) == + (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP)) + eb |= 1u << BP_VECTOR; + if (to_vmx(vcpu)->rmode.vm86_active) + eb = ~0; + if (enable_ept) + eb &= ~(1u << PF_VECTOR); /* bypass_guest_pf = 0 */ + + /* When we are running a nested L2 guest and L1 specified for it a + * certain exception bitmap, we must trap the same exceptions and pass + * them to L1. When running L2, we will only handle the exceptions + * specified above if L1 did not want them. + */ + if (is_guest_mode(vcpu)) + eb |= get_vmcs12(vcpu)->exception_bitmap; + + vmcs_write32(EXCEPTION_BITMAP, eb); +} + +/* + * Check if MSR is intercepted for currently loaded MSR bitmap. + */ +static bool msr_write_intercepted(struct kvm_vcpu *vcpu, u32 msr) +{ + unsigned long *msr_bitmap; + int f = sizeof(unsigned long); + + if (!cpu_has_vmx_msr_bitmap()) + return true; + + msr_bitmap = to_vmx(vcpu)->loaded_vmcs->msr_bitmap; + + if (msr <= 0x1fff) { + return !!test_bit(msr, msr_bitmap + 0x800 / f); + } else if ((msr >= 0xc0000000) && (msr <= 0xc0001fff)) { + msr &= 0x1fff; + return !!test_bit(msr, msr_bitmap + 0xc00 / f); + } + + return true; +} + +static void clear_atomic_switch_msr_special(struct vcpu_vmx *vmx, + unsigned long entry, unsigned long exit) +{ + vm_entry_controls_clearbit(vmx, entry); + vm_exit_controls_clearbit(vmx, exit); +} + +int vmx_find_msr_index(struct vmx_msrs *m, u32 msr) +{ + unsigned int i; + + for (i = 0; i < m->nr; ++i) { + if (m->val[i].index == msr) + return i; + } + return -ENOENT; +} + +static void clear_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr) +{ + int i; + struct msr_autoload *m = &vmx->msr_autoload; + + switch (msr) { + case MSR_EFER: + if (cpu_has_load_ia32_efer()) { + clear_atomic_switch_msr_special(vmx, + VM_ENTRY_LOAD_IA32_EFER, + VM_EXIT_LOAD_IA32_EFER); + return; + } + break; + case MSR_CORE_PERF_GLOBAL_CTRL: + if (cpu_has_load_perf_global_ctrl()) { + clear_atomic_switch_msr_special(vmx, + VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL, + VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL); + return; + } + break; + } + i = vmx_find_msr_index(&m->guest, msr); + if (i < 0) + goto skip_guest; + --m->guest.nr; + m->guest.val[i] = m->guest.val[m->guest.nr]; + vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr); + +skip_guest: + i = vmx_find_msr_index(&m->host, msr); + if (i < 0) + return; + + --m->host.nr; + m->host.val[i] = m->host.val[m->host.nr]; + vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->host.nr); +} + +static void add_atomic_switch_msr_special(struct vcpu_vmx *vmx, + unsigned long entry, unsigned long exit, + unsigned long guest_val_vmcs, unsigned long host_val_vmcs, + u64 guest_val, u64 host_val) +{ + vmcs_write64(guest_val_vmcs, guest_val); + if (host_val_vmcs != HOST_IA32_EFER) + vmcs_write64(host_val_vmcs, host_val); + vm_entry_controls_setbit(vmx, entry); + vm_exit_controls_setbit(vmx, exit); +} + +static void add_atomic_switch_msr(struct vcpu_vmx *vmx, unsigned msr, + u64 guest_val, u64 host_val, bool entry_only) +{ + int i, j = 0; + struct msr_autoload *m = &vmx->msr_autoload; + + switch (msr) { + case MSR_EFER: + if (cpu_has_load_ia32_efer()) { + add_atomic_switch_msr_special(vmx, + VM_ENTRY_LOAD_IA32_EFER, + VM_EXIT_LOAD_IA32_EFER, + GUEST_IA32_EFER, + HOST_IA32_EFER, + guest_val, host_val); + return; + } + break; + case MSR_CORE_PERF_GLOBAL_CTRL: + if (cpu_has_load_perf_global_ctrl()) { + add_atomic_switch_msr_special(vmx, + VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL, + VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL, + GUEST_IA32_PERF_GLOBAL_CTRL, + HOST_IA32_PERF_GLOBAL_CTRL, + guest_val, host_val); + return; + } + break; + case MSR_IA32_PEBS_ENABLE: + /* PEBS needs a quiescent period after being disabled (to write + * a record). Disabling PEBS through VMX MSR swapping doesn't + * provide that period, so a CPU could write host's record into + * guest's memory. + */ + wrmsrl(MSR_IA32_PEBS_ENABLE, 0); + } + + i = vmx_find_msr_index(&m->guest, msr); + if (!entry_only) + j = vmx_find_msr_index(&m->host, msr); + + if ((i < 0 && m->guest.nr == NR_LOADSTORE_MSRS) || + (j < 0 && m->host.nr == NR_LOADSTORE_MSRS)) { + printk_once(KERN_WARNING "Not enough msr switch entries. " + "Can't add msr %x\n", msr); + return; + } + if (i < 0) { + i = m->guest.nr++; + vmcs_write32(VM_ENTRY_MSR_LOAD_COUNT, m->guest.nr); + } + m->guest.val[i].index = msr; + m->guest.val[i].value = guest_val; + + if (entry_only) + return; + + if (j < 0) { + j = m->host.nr++; + vmcs_write32(VM_EXIT_MSR_LOAD_COUNT, m->host.nr); + } + m->host.val[j].index = msr; + m->host.val[j].value = host_val; +} + +static bool update_transition_efer(struct vcpu_vmx *vmx, int efer_offset) +{ + u64 guest_efer = vmx->vcpu.arch.efer; + u64 ignore_bits = 0; + + /* Shadow paging assumes NX to be available. */ + if (!enable_ept) + guest_efer |= EFER_NX; + + /* + * LMA and LME handled by hardware; SCE meaningless outside long mode. + */ + ignore_bits |= EFER_SCE; +#ifdef CONFIG_X86_64 + ignore_bits |= EFER_LMA | EFER_LME; + /* SCE is meaningful only in long mode on Intel */ + if (guest_efer & EFER_LMA) + ignore_bits &= ~(u64)EFER_SCE; +#endif + + /* + * On EPT, we can't emulate NX, so we must switch EFER atomically. + * On CPUs that support "load IA32_EFER", always switch EFER + * atomically, since it's faster than switching it manually. + */ + if (cpu_has_load_ia32_efer() || + (enable_ept && ((vmx->vcpu.arch.efer ^ host_efer) & EFER_NX))) { + if (!(guest_efer & EFER_LMA)) + guest_efer &= ~EFER_LME; + if (guest_efer != host_efer) + add_atomic_switch_msr(vmx, MSR_EFER, + guest_efer, host_efer, false); + else + clear_atomic_switch_msr(vmx, MSR_EFER); + return false; + } else { + clear_atomic_switch_msr(vmx, MSR_EFER); + + guest_efer &= ~ignore_bits; + guest_efer |= host_efer & ignore_bits; + + vmx->guest_msrs[efer_offset].data = guest_efer; + vmx->guest_msrs[efer_offset].mask = ~ignore_bits; + + return true; + } +} + +#ifdef CONFIG_X86_32 +/* + * On 32-bit kernels, VM exits still load the FS and GS bases from the + * VMCS rather than the segment table. KVM uses this helper to figure + * out the current bases to poke them into the VMCS before entry. + */ +static unsigned long segment_base(u16 selector) +{ + struct desc_struct *table; + unsigned long v; + + if (!(selector & ~SEGMENT_RPL_MASK)) + return 0; + + table = get_current_gdt_ro(); + + if ((selector & SEGMENT_TI_MASK) == SEGMENT_LDT) { + u16 ldt_selector = kvm_read_ldt(); + + if (!(ldt_selector & ~SEGMENT_RPL_MASK)) + return 0; + + table = (struct desc_struct *)segment_base(ldt_selector); + } + v = get_desc_base(&table[selector >> 3]); + return v; +} +#endif + +static inline void pt_load_msr(struct pt_ctx *ctx, u32 addr_range) +{ + u32 i; + + wrmsrl(MSR_IA32_RTIT_STATUS, ctx->status); + wrmsrl(MSR_IA32_RTIT_OUTPUT_BASE, ctx->output_base); + wrmsrl(MSR_IA32_RTIT_OUTPUT_MASK, ctx->output_mask); + wrmsrl(MSR_IA32_RTIT_CR3_MATCH, ctx->cr3_match); + for (i = 0; i < addr_range; i++) { + wrmsrl(MSR_IA32_RTIT_ADDR0_A + i * 2, ctx->addr_a[i]); + wrmsrl(MSR_IA32_RTIT_ADDR0_B + i * 2, ctx->addr_b[i]); + } +} + +static inline void pt_save_msr(struct pt_ctx *ctx, u32 addr_range) +{ + u32 i; + + rdmsrl(MSR_IA32_RTIT_STATUS, ctx->status); + rdmsrl(MSR_IA32_RTIT_OUTPUT_BASE, ctx->output_base); + rdmsrl(MSR_IA32_RTIT_OUTPUT_MASK, ctx->output_mask); + rdmsrl(MSR_IA32_RTIT_CR3_MATCH, ctx->cr3_match); + for (i = 0; i < addr_range; i++) { + rdmsrl(MSR_IA32_RTIT_ADDR0_A + i * 2, ctx->addr_a[i]); + rdmsrl(MSR_IA32_RTIT_ADDR0_B + i * 2, ctx->addr_b[i]); + } +} + +static void pt_guest_enter(struct vcpu_vmx *vmx) +{ + if (pt_mode == PT_MODE_SYSTEM) + return; + + /* + * GUEST_IA32_RTIT_CTL is already set in the VMCS. + * Save host state before VM entry. + */ + rdmsrl(MSR_IA32_RTIT_CTL, vmx->pt_desc.host.ctl); + if (vmx->pt_desc.guest.ctl & RTIT_CTL_TRACEEN) { + wrmsrl(MSR_IA32_RTIT_CTL, 0); + pt_save_msr(&vmx->pt_desc.host, vmx->pt_desc.addr_range); + pt_load_msr(&vmx->pt_desc.guest, vmx->pt_desc.addr_range); + } +} + +static void pt_guest_exit(struct vcpu_vmx *vmx) +{ + if (pt_mode == PT_MODE_SYSTEM) + return; + + if (vmx->pt_desc.guest.ctl & RTIT_CTL_TRACEEN) { + pt_save_msr(&vmx->pt_desc.guest, vmx->pt_desc.addr_range); + pt_load_msr(&vmx->pt_desc.host, vmx->pt_desc.addr_range); + } + + /* Reload host state (IA32_RTIT_CTL will be cleared on VM exit). */ + wrmsrl(MSR_IA32_RTIT_CTL, vmx->pt_desc.host.ctl); +} + +void vmx_set_host_fs_gs(struct vmcs_host_state *host, u16 fs_sel, u16 gs_sel, + unsigned long fs_base, unsigned long gs_base) +{ + if (unlikely(fs_sel != host->fs_sel)) { + if (!(fs_sel & 7)) + vmcs_write16(HOST_FS_SELECTOR, fs_sel); + else + vmcs_write16(HOST_FS_SELECTOR, 0); + host->fs_sel = fs_sel; + } + if (unlikely(gs_sel != host->gs_sel)) { + if (!(gs_sel & 7)) + vmcs_write16(HOST_GS_SELECTOR, gs_sel); + else + vmcs_write16(HOST_GS_SELECTOR, 0); + host->gs_sel = gs_sel; + } + if (unlikely(fs_base != host->fs_base)) { + vmcs_writel(HOST_FS_BASE, fs_base); + host->fs_base = fs_base; + } + if (unlikely(gs_base != host->gs_base)) { + vmcs_writel(HOST_GS_BASE, gs_base); + host->gs_base = gs_base; + } +} + +void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + struct vmcs_host_state *host_state; +#ifdef CONFIG_X86_64 + int cpu = raw_smp_processor_id(); +#endif + unsigned long fs_base, gs_base; + u16 fs_sel, gs_sel; + int i; + + vmx->req_immediate_exit = false; + + /* + * Note that guest MSRs to be saved/restored can also be changed + * when guest state is loaded. This happens when guest transitions + * to/from long-mode by setting MSR_EFER.LMA. + */ + if (!vmx->guest_msrs_ready) { + vmx->guest_msrs_ready = true; + for (i = 0; i < vmx->save_nmsrs; ++i) + kvm_set_shared_msr(vmx->guest_msrs[i].index, + vmx->guest_msrs[i].data, + vmx->guest_msrs[i].mask); + + } + if (vmx->guest_state_loaded) + return; + + host_state = &vmx->loaded_vmcs->host_state; + + /* + * Set host fs and gs selectors. Unfortunately, 22.2.3 does not + * allow segment selectors with cpl > 0 or ti == 1. + */ + host_state->ldt_sel = kvm_read_ldt(); + +#ifdef CONFIG_X86_64 + savesegment(ds, host_state->ds_sel); + savesegment(es, host_state->es_sel); + + gs_base = cpu_kernelmode_gs_base(cpu); + if (likely(is_64bit_mm(current->mm))) { + save_fsgs_for_kvm(); + fs_sel = current->thread.fsindex; + gs_sel = current->thread.gsindex; + fs_base = current->thread.fsbase; + vmx->msr_host_kernel_gs_base = current->thread.gsbase; + } else { + savesegment(fs, fs_sel); + savesegment(gs, gs_sel); + fs_base = read_msr(MSR_FS_BASE); + vmx->msr_host_kernel_gs_base = read_msr(MSR_KERNEL_GS_BASE); + } + + wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base); +#else + savesegment(fs, fs_sel); + savesegment(gs, gs_sel); + fs_base = segment_base(fs_sel); + gs_base = segment_base(gs_sel); +#endif + + vmx_set_host_fs_gs(host_state, fs_sel, gs_sel, fs_base, gs_base); + vmx->guest_state_loaded = true; +} + +static void vmx_prepare_switch_to_host(struct vcpu_vmx *vmx) +{ + struct vmcs_host_state *host_state; + + if (!vmx->guest_state_loaded) + return; + + host_state = &vmx->loaded_vmcs->host_state; + + ++vmx->vcpu.stat.host_state_reload; + +#ifdef CONFIG_X86_64 + rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base); +#endif + if (host_state->ldt_sel || (host_state->gs_sel & 7)) { + kvm_load_ldt(host_state->ldt_sel); +#ifdef CONFIG_X86_64 + load_gs_index(host_state->gs_sel); +#else + loadsegment(gs, host_state->gs_sel); +#endif + } + if (host_state->fs_sel & 7) + loadsegment(fs, host_state->fs_sel); +#ifdef CONFIG_X86_64 + if (unlikely(host_state->ds_sel | host_state->es_sel)) { + loadsegment(ds, host_state->ds_sel); + loadsegment(es, host_state->es_sel); + } +#endif + invalidate_tss_limit(); +#ifdef CONFIG_X86_64 + wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_host_kernel_gs_base); +#endif + load_fixmap_gdt(raw_smp_processor_id()); + vmx->guest_state_loaded = false; + vmx->guest_msrs_ready = false; +} + +#ifdef CONFIG_X86_64 +static u64 vmx_read_guest_kernel_gs_base(struct vcpu_vmx *vmx) +{ + preempt_disable(); + if (vmx->guest_state_loaded) + rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base); + preempt_enable(); + return vmx->msr_guest_kernel_gs_base; +} + +static void vmx_write_guest_kernel_gs_base(struct vcpu_vmx *vmx, u64 data) +{ + preempt_disable(); + if (vmx->guest_state_loaded) + wrmsrl(MSR_KERNEL_GS_BASE, data); + preempt_enable(); + vmx->msr_guest_kernel_gs_base = data; +} +#endif + +static void vmx_vcpu_pi_load(struct kvm_vcpu *vcpu, int cpu) +{ + struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu); + struct pi_desc old, new; + unsigned int dest; + + /* + * In case of hot-plug or hot-unplug, we may have to undo + * vmx_vcpu_pi_put even if there is no assigned device. And we + * always keep PI.NDST up to date for simplicity: it makes the + * code easier, and CPU migration is not a fast path. + */ + if (!pi_test_sn(pi_desc) && vcpu->cpu == cpu) + return; + + /* + * If the 'nv' field is POSTED_INTR_WAKEUP_VECTOR, do not change + * PI.NDST: pi_post_block is the one expected to change PID.NDST and the + * wakeup handler expects the vCPU to be on the blocked_vcpu_list that + * matches PI.NDST. Otherwise, a vcpu may not be able to be woken up + * correctly. + */ + if (pi_desc->nv == POSTED_INTR_WAKEUP_VECTOR || vcpu->cpu == cpu) { + pi_clear_sn(pi_desc); + goto after_clear_sn; + } + + /* The full case. */ + do { + old.control = new.control = pi_desc->control; + + dest = cpu_physical_id(cpu); + + if (x2apic_enabled()) + new.ndst = dest; + else + new.ndst = (dest << 8) & 0xFF00; + + new.sn = 0; + } while (cmpxchg64(&pi_desc->control, old.control, + new.control) != old.control); + +after_clear_sn: + + /* + * Clear SN before reading the bitmap. The VT-d firmware + * writes the bitmap and reads SN atomically (5.2.3 in the + * spec), so it doesn't really have a memory barrier that + * pairs with this, but we cannot do that and we need one. + */ + smp_mb__after_atomic(); + + if (!pi_is_pir_empty(pi_desc)) + pi_set_on(pi_desc); +} + +void vmx_vcpu_load_vmcs(struct kvm_vcpu *vcpu, int cpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + bool already_loaded = vmx->loaded_vmcs->cpu == cpu; + + if (!already_loaded) { + loaded_vmcs_clear(vmx->loaded_vmcs); + local_irq_disable(); + crash_disable_local_vmclear(cpu); + + /* + * Read loaded_vmcs->cpu should be before fetching + * loaded_vmcs->loaded_vmcss_on_cpu_link. + * See the comments in __loaded_vmcs_clear(). + */ + smp_rmb(); + + list_add(&vmx->loaded_vmcs->loaded_vmcss_on_cpu_link, + &per_cpu(loaded_vmcss_on_cpu, cpu)); + crash_enable_local_vmclear(cpu); + local_irq_enable(); + } + + if (per_cpu(current_vmcs, cpu) != vmx->loaded_vmcs->vmcs) { + per_cpu(current_vmcs, cpu) = vmx->loaded_vmcs->vmcs; + vmcs_load(vmx->loaded_vmcs->vmcs); + indirect_branch_prediction_barrier(); + } + + if (!already_loaded) { + void *gdt = get_current_gdt_ro(); + unsigned long sysenter_esp; + + kvm_make_request(KVM_REQ_TLB_FLUSH, vcpu); + + /* + * Linux uses per-cpu TSS and GDT, so set these when switching + * processors. See 22.2.4. + */ + vmcs_writel(HOST_TR_BASE, + (unsigned long)&get_cpu_entry_area(cpu)->tss.x86_tss); + vmcs_writel(HOST_GDTR_BASE, (unsigned long)gdt); /* 22.2.4 */ + + rdmsrl(MSR_IA32_SYSENTER_ESP, sysenter_esp); + vmcs_writel(HOST_IA32_SYSENTER_ESP, sysenter_esp); /* 22.2.3 */ + + vmx->loaded_vmcs->cpu = cpu; + } + + /* Setup TSC multiplier */ + if (kvm_has_tsc_control && + vmx->current_tsc_ratio != vcpu->arch.tsc_scaling_ratio) + decache_tsc_multiplier(vmx); +} + +/* + * Switches to specified vcpu, until a matching vcpu_put(), but assumes + * vcpu mutex is already taken. + */ +void vmx_vcpu_load(struct kvm_vcpu *vcpu, int cpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + vmx_vcpu_load_vmcs(vcpu, cpu); + + vmx_vcpu_pi_load(vcpu, cpu); + + vmx->host_pkru = read_pkru(); + vmx->host_debugctlmsr = get_debugctlmsr(); +} + +static void vmx_vcpu_pi_put(struct kvm_vcpu *vcpu) +{ + struct pi_desc *pi_desc = vcpu_to_pi_desc(vcpu); + + if (!kvm_arch_has_assigned_device(vcpu->kvm) || + !irq_remapping_cap(IRQ_POSTING_CAP) || + !kvm_vcpu_apicv_active(vcpu)) + return; + + /* Set SN when the vCPU is preempted */ + if (vcpu->preempted) + pi_set_sn(pi_desc); +} + +static void vmx_vcpu_put(struct kvm_vcpu *vcpu) +{ + vmx_vcpu_pi_put(vcpu); + + vmx_prepare_switch_to_host(to_vmx(vcpu)); +} + +static bool emulation_required(struct kvm_vcpu *vcpu) +{ + return emulate_invalid_guest_state && !guest_state_valid(vcpu); +} + +static void vmx_decache_cr0_guest_bits(struct kvm_vcpu *vcpu); + +unsigned long vmx_get_rflags(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + unsigned long rflags, save_rflags; + + if (!kvm_register_is_available(vcpu, VCPU_EXREG_RFLAGS)) { + kvm_register_mark_available(vcpu, VCPU_EXREG_RFLAGS); + rflags = vmcs_readl(GUEST_RFLAGS); + if (vmx->rmode.vm86_active) { + rflags &= RMODE_GUEST_OWNED_EFLAGS_BITS; + save_rflags = vmx->rmode.save_rflags; + rflags |= save_rflags & ~RMODE_GUEST_OWNED_EFLAGS_BITS; + } + vmx->rflags = rflags; + } + return vmx->rflags; +} + +void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + unsigned long old_rflags; + + if (enable_unrestricted_guest) { + kvm_register_mark_available(vcpu, VCPU_EXREG_RFLAGS); + vmx->rflags = rflags; + vmcs_writel(GUEST_RFLAGS, rflags); + return; + } + + old_rflags = vmx_get_rflags(vcpu); + vmx->rflags = rflags; + if (vmx->rmode.vm86_active) { + vmx->rmode.save_rflags = rflags; + rflags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM; + } + vmcs_writel(GUEST_RFLAGS, rflags); + + if ((old_rflags ^ vmx->rflags) & X86_EFLAGS_VM) + vmx->emulation_required = emulation_required(vcpu); +} + +u32 vmx_get_interrupt_shadow(struct kvm_vcpu *vcpu) +{ + u32 interruptibility = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); + int ret = 0; + + if (interruptibility & GUEST_INTR_STATE_STI) + ret |= KVM_X86_SHADOW_INT_STI; + if (interruptibility & GUEST_INTR_STATE_MOV_SS) + ret |= KVM_X86_SHADOW_INT_MOV_SS; + + return ret; +} + +void vmx_set_interrupt_shadow(struct kvm_vcpu *vcpu, int mask) +{ + u32 interruptibility_old = vmcs_read32(GUEST_INTERRUPTIBILITY_INFO); + u32 interruptibility = interruptibility_old; + + interruptibility &= ~(GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS); + + if (mask & KVM_X86_SHADOW_INT_MOV_SS) + interruptibility |= GUEST_INTR_STATE_MOV_SS; + else if (mask & KVM_X86_SHADOW_INT_STI) + interruptibility |= GUEST_INTR_STATE_STI; + + if ((interruptibility != interruptibility_old)) + vmcs_write32(GUEST_INTERRUPTIBILITY_INFO, interruptibility); +} + +static int vmx_rtit_ctl_check(struct kvm_vcpu *vcpu, u64 data) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + unsigned long value; + + /* + * Any MSR write that attempts to change bits marked reserved will + * case a #GP fault. + */ + if (data & vmx->pt_desc.ctl_bitmask) + return 1; + + /* + * Any attempt to modify IA32_RTIT_CTL while TraceEn is set will + * result in a #GP unless the same write also clears TraceEn. + */ + if ((vmx->pt_desc.guest.ctl & RTIT_CTL_TRACEEN) && + ((vmx->pt_desc.guest.ctl ^ data) & ~RTIT_CTL_TRACEEN)) + return 1; + + /* + * WRMSR to IA32_RTIT_CTL that sets TraceEn but clears this bit + * and FabricEn would cause #GP, if + * CPUID.(EAX=14H, ECX=0):ECX.SNGLRGNOUT[bit 2] = 0 + */ + if ((data & RTIT_CTL_TRACEEN) && !(data & RTIT_CTL_TOPA) && + !(data & RTIT_CTL_FABRIC_EN) && + !intel_pt_validate_cap(vmx->pt_desc.caps, + PT_CAP_single_range_output)) + return 1; + + /* + * MTCFreq, CycThresh and PSBFreq encodings check, any MSR write that + * utilize encodings marked reserved will casue a #GP fault. + */ + value = intel_pt_validate_cap(vmx->pt_desc.caps, PT_CAP_mtc_periods); + if (intel_pt_validate_cap(vmx->pt_desc.caps, PT_CAP_mtc) && + !test_bit((data & RTIT_CTL_MTC_RANGE) >> + RTIT_CTL_MTC_RANGE_OFFSET, &value)) + return 1; + value = intel_pt_validate_cap(vmx->pt_desc.caps, + PT_CAP_cycle_thresholds); + if (intel_pt_validate_cap(vmx->pt_desc.caps, PT_CAP_psb_cyc) && + !test_bit((data & RTIT_CTL_CYC_THRESH) >> + RTIT_CTL_CYC_THRESH_OFFSET, &value)) + return 1; + value = intel_pt_validate_cap(vmx->pt_desc.caps, PT_CAP_psb_periods); + if (intel_pt_validate_cap(vmx->pt_desc.caps, PT_CAP_psb_cyc) && + !test_bit((data & RTIT_CTL_PSB_FREQ) >> + RTIT_CTL_PSB_FREQ_OFFSET, &value)) + return 1; + + /* + * If ADDRx_CFG is reserved or the encodings is >2 will + * cause a #GP fault. + */ + value = (data & RTIT_CTL_ADDR0) >> RTIT_CTL_ADDR0_OFFSET; + if ((value && (vmx->pt_desc.addr_range < 1)) || (value > 2)) + return 1; + value = (data & RTIT_CTL_ADDR1) >> RTIT_CTL_ADDR1_OFFSET; + if ((value && (vmx->pt_desc.addr_range < 2)) || (value > 2)) + return 1; + value = (data & RTIT_CTL_ADDR2) >> RTIT_CTL_ADDR2_OFFSET; + if ((value && (vmx->pt_desc.addr_range < 3)) || (value > 2)) + return 1; + value = (data & RTIT_CTL_ADDR3) >> RTIT_CTL_ADDR3_OFFSET; + if ((value && (vmx->pt_desc.addr_range < 4)) || (value > 2)) + return 1; + + return 0; +} + +static int skip_emulated_instruction(struct kvm_vcpu *vcpu) +{ + unsigned long rip; + + /* + * Using VMCS.VM_EXIT_INSTRUCTION_LEN on EPT misconfig depends on + * undefined behavior: Intel's SDM doesn't mandate the VMCS field be + * set when EPT misconfig occurs. In practice, real hardware updates + * VM_EXIT_INSTRUCTION_LEN on EPT misconfig, but other hypervisors + * (namely Hyper-V) don't set it due to it being undefined behavior, + * i.e. we end up advancing IP with some random value. + */ + if (!static_cpu_has(X86_FEATURE_HYPERVISOR) || + to_vmx(vcpu)->exit_reason != EXIT_REASON_EPT_MISCONFIG) { + rip = kvm_rip_read(vcpu); + rip += vmcs_read32(VM_EXIT_INSTRUCTION_LEN); + kvm_rip_write(vcpu, rip); + } else { + if (!kvm_emulate_instruction(vcpu, EMULTYPE_SKIP)) + return 0; + } + + /* skipping an emulated instruction also counts */ + vmx_set_interrupt_shadow(vcpu, 0); + + return 1; +} + +static void vmx_clear_hlt(struct kvm_vcpu *vcpu) +{ + /* + * Ensure that we clear the HLT state in the VMCS. We don't need to + * explicitly skip the instruction because if the HLT state is set, + * then the instruction is already executing and RIP has already been + * advanced. + */ + if (kvm_hlt_in_guest(vcpu->kvm) && + vmcs_read32(GUEST_ACTIVITY_STATE) == GUEST_ACTIVITY_HLT) + vmcs_write32(GUEST_ACTIVITY_STATE, GUEST_ACTIVITY_ACTIVE); +} + +static void vmx_queue_exception(struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + unsigned nr = vcpu->arch.exception.nr; + bool has_error_code = vcpu->arch.exception.has_error_code; + u32 error_code = vcpu->arch.exception.error_code; + u32 intr_info = nr | INTR_INFO_VALID_MASK; + + kvm_deliver_exception_payload(vcpu); + + if (has_error_code) { + vmcs_write32(VM_ENTRY_EXCEPTION_ERROR_CODE, error_code); + intr_info |= INTR_INFO_DELIVER_CODE_MASK; + } + + if (vmx->rmode.vm86_active) { + int inc_eip = 0; + if (kvm_exception_is_soft(nr)) + inc_eip = vcpu->arch.event_exit_inst_len; + kvm_inject_realmode_interrupt(vcpu, nr, inc_eip); + return; + } + + WARN_ON_ONCE(vmx->emulation_required); + + if (kvm_exception_is_soft(nr)) { + vmcs_write32(VM_ENTRY_INSTRUCTION_LEN, + vmx->vcpu.arch.event_exit_inst_len); + intr_info |= INTR_TYPE_SOFT_EXCEPTION; + } else + intr_info |= INTR_TYPE_HARD_EXCEPTION; + + vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info); + + vmx_clear_hlt(vcpu); +} + +static bool vmx_rdtscp_supported(void) +{ + return cpu_has_vmx_rdtscp(); +} + +static bool vmx_invpcid_supported(void) +{ + return cpu_has_vmx_invpcid(); +} + +/* + * Swap MSR entry in host/guest MSR entry array. + */ +static void move_msr_up(struct vcpu_vmx *vmx, int from, int to) +{ + struct shared_msr_entry tmp; + + tmp = vmx->guest_msrs[to]; + vmx->guest_msrs[to] = vmx->guest_msrs[from]; + vmx->guest_msrs[from] = tmp; +} + +/* + * Set up the vmcs to automatically save and restore system + * msrs. Don't touch the 64-bit msrs if the guest is in legacy + * mode, as fiddling with msrs is very expensive. + */ +static void setup_msrs(struct vcpu_vmx *vmx) +{ + int save_nmsrs, index; + + save_nmsrs = 0; +#ifdef CONFIG_X86_64 + /* + * The SYSCALL MSRs are only needed on long mode guests, and only + * when EFER.SCE is set. + */ + if (is_long_mode(&vmx->vcpu) && (vmx->vcpu.arch.efer & EFER_SCE)) { + index = __find_msr_index(vmx, MSR_STAR); + if (index >= 0) + move_msr_up(vmx, index, save_nmsrs++); + index = __find_msr_index(vmx, MSR_LSTAR); + if (index >= 0) + move_msr_up(vmx, index, save_nmsrs++); + index = __find_msr_index(vmx, MSR_SYSCALL_MASK); + if (index >= 0) + move_msr_up(vmx, index, save_nmsrs++); + } +#endif + index = __find_msr_index(vmx, MSR_EFER); + if (index >= 0 && update_transition_efer(vmx, index)) + move_msr_up(vmx, index, save_nmsrs++); + index = __find_msr_index(vmx, MSR_TSC_AUX); + if (index >= 0 && guest_cpuid_has(&vmx->vcpu, X86_FEATURE_RDTSCP)) + move_msr_up(vmx, index, save_nmsrs++); + index = __find_msr_index(vmx, MSR_IA32_TSX_CTRL); + if (index >= 0) + move_msr_up(vmx, index, save_nmsrs++); + + vmx->save_nmsrs = save_nmsrs; + vmx->guest_msrs_ready = false; + + if (cpu_has_vmx_msr_bitmap()) + vmx_update_msr_bitmap(&vmx->vcpu); +} + +static u64 vmx_read_l1_tsc_offset(struct kvm_vcpu *vcpu) +{ + struct vmcs12 *vmcs12 = get_vmcs12(vcpu); + + if (is_guest_mode(vcpu) && + (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETTING)) + return vcpu->arch.tsc_offset - vmcs12->tsc_offset; + + return vcpu->arch.tsc_offset; +} + +static u64 vmx_write_l1_tsc_offset(struct kvm_vcpu *vcpu, u64 offset) +{ + struct vmcs12 *vmcs12 = get_vmcs12(vcpu); + u64 g_tsc_offset = 0; + + /* + * We're here if L1 chose not to trap WRMSR to TSC. According + * to the spec, this should set L1's TSC; The offset that L1 + * set for L2 remains unchanged, and still needs to be added + * to the newly set TSC to get L2's TSC. + */ + if (is_guest_mode(vcpu) && + (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETTING)) + g_tsc_offset = vmcs12->tsc_offset; + + trace_kvm_write_tsc_offset(vcpu->vcpu_id, + vcpu->arch.tsc_offset - g_tsc_offset, + offset); + vmcs_write64(TSC_OFFSET, offset + g_tsc_offset); + return offset + g_tsc_offset; +} + +/* + * nested_vmx_allowed() checks whether a guest should be allowed to use VMX + * instructions and MSRs (i.e., nested VMX). Nested VMX is disabled for + * all guests if the "nested" module option is off, and can also be disabled + * for a single guest by disabling its VMX cpuid bit. + */ +bool nested_vmx_allowed(struct kvm_vcpu *vcpu) +{ + return nested && guest_cpuid_has(vcpu, X86_FEATURE_VMX); +} + +static inline bool vmx_feature_control_msr_valid(struct kvm_vcpu *vcpu, + uint64_t val) +{ + uint64_t valid_bits = to_vmx(vcpu)->msr_ia32_feature_control_valid_bits; + + return !(val & ~valid_bits); +} + +static int vmx_get_msr_feature(struct kvm_msr_entry *msr) +{ + switch (msr->index) { + case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC: + if (!nested) + return 1; + return vmx_get_vmx_msr(&vmcs_config.nested, msr->index, &msr->data); + default: + return 1; + } +} + +/* + * Reads an msr value (of 'msr_index') into 'pdata'. + * Returns 0 on success, non-0 otherwise. + * Assumes vcpu_load() was already called. + */ +static int vmx_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + struct shared_msr_entry *msr; + u32 index; + + switch (msr_info->index) { +#ifdef CONFIG_X86_64 + case MSR_FS_BASE: + msr_info->data = vmcs_readl(GUEST_FS_BASE); + break; + case MSR_GS_BASE: + msr_info->data = vmcs_readl(GUEST_GS_BASE); + break; + case MSR_KERNEL_GS_BASE: + msr_info->data = vmx_read_guest_kernel_gs_base(vmx); + break; +#endif + case MSR_EFER: + return kvm_get_msr_common(vcpu, msr_info); + case MSR_IA32_TSX_CTRL: + if (!msr_info->host_initiated && + !(vcpu->arch.arch_capabilities & ARCH_CAP_TSX_CTRL_MSR)) + return 1; + goto find_shared_msr; + case MSR_IA32_UMWAIT_CONTROL: + if (!msr_info->host_initiated && !vmx_has_waitpkg(vmx)) + return 1; + + msr_info->data = vmx->msr_ia32_umwait_control; + break; + case MSR_IA32_SPEC_CTRL: + if (!msr_info->host_initiated && + !guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL)) + return 1; + + msr_info->data = to_vmx(vcpu)->spec_ctrl; + break; + case MSR_IA32_SYSENTER_CS: + msr_info->data = vmcs_read32(GUEST_SYSENTER_CS); + break; + case MSR_IA32_SYSENTER_EIP: + msr_info->data = vmcs_readl(GUEST_SYSENTER_EIP); + break; + case MSR_IA32_SYSENTER_ESP: + msr_info->data = vmcs_readl(GUEST_SYSENTER_ESP); + break; + case MSR_IA32_BNDCFGS: + if (!kvm_mpx_supported() || + (!msr_info->host_initiated && + !guest_cpuid_has(vcpu, X86_FEATURE_MPX))) + return 1; + msr_info->data = vmcs_read64(GUEST_BNDCFGS); + break; + case MSR_IA32_MCG_EXT_CTL: + if (!msr_info->host_initiated && + !(vmx->msr_ia32_feature_control & + FEATURE_CONTROL_LMCE)) + return 1; + msr_info->data = vcpu->arch.mcg_ext_ctl; + break; + case MSR_IA32_FEATURE_CONTROL: + msr_info->data = vmx->msr_ia32_feature_control; + break; + case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC: + if (!nested_vmx_allowed(vcpu)) + return 1; + return vmx_get_vmx_msr(&vmx->nested.msrs, msr_info->index, + &msr_info->data); + case MSR_IA32_RTIT_CTL: + if (pt_mode != PT_MODE_HOST_GUEST) + return 1; + msr_info->data = vmx->pt_desc.guest.ctl; + break; + case MSR_IA32_RTIT_STATUS: + if (pt_mode != PT_MODE_HOST_GUEST) + return 1; + msr_info->data = vmx->pt_desc.guest.status; + break; + case MSR_IA32_RTIT_CR3_MATCH: + if ((pt_mode != PT_MODE_HOST_GUEST) || + !intel_pt_validate_cap(vmx->pt_desc.caps, + PT_CAP_cr3_filtering)) + return 1; + msr_info->data = vmx->pt_desc.guest.cr3_match; + break; + case MSR_IA32_RTIT_OUTPUT_BASE: + if ((pt_mode != PT_MODE_HOST_GUEST) || + (!intel_pt_validate_cap(vmx->pt_desc.caps, + PT_CAP_topa_output) && + !intel_pt_validate_cap(vmx->pt_desc.caps, + PT_CAP_single_range_output))) + return 1; + msr_info->data = vmx->pt_desc.guest.output_base; + break; + case MSR_IA32_RTIT_OUTPUT_MASK: + if ((pt_mode != PT_MODE_HOST_GUEST) || + (!intel_pt_validate_cap(vmx->pt_desc.caps, + PT_CAP_topa_output) && + !intel_pt_validate_cap(vmx->pt_desc.caps, + PT_CAP_single_range_output))) + return 1; + msr_info->data = vmx->pt_desc.guest.output_mask; + break; + case MSR_IA32_RTIT_ADDR0_A ... MSR_IA32_RTIT_ADDR3_B: + index = msr_info->index - MSR_IA32_RTIT_ADDR0_A; + if ((pt_mode != PT_MODE_HOST_GUEST) || + (index >= 2 * intel_pt_validate_cap(vmx->pt_desc.caps, + PT_CAP_num_address_ranges))) + return 1; + if (is_noncanonical_address(data, vcpu)) + return 1; + if (index % 2) + msr_info->data = vmx->pt_desc.guest.addr_b[index / 2]; + else + msr_info->data = vmx->pt_desc.guest.addr_a[index / 2]; + break; + case MSR_TSC_AUX: + if (!msr_info->host_initiated && + !guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP)) + return 1; + goto find_shared_msr; + default: + find_shared_msr: + msr = find_msr_entry(vmx, msr_info->index); + if (msr) { + msr_info->data = msr->data; + break; + } + return kvm_get_msr_common(vcpu, msr_info); + } + + return 0; +} + +/* + * Writes msr value into the appropriate "register". + * Returns 0 on success, non-0 otherwise. + * Assumes vcpu_load() was already called. + */ +static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + struct shared_msr_entry *msr; + int ret = 0; + u32 msr_index = msr_info->index; + u64 data = msr_info->data; + u32 index; + + switch (msr_index) { + case MSR_EFER: + ret = kvm_set_msr_common(vcpu, msr_info); + break; +#ifdef CONFIG_X86_64 + case MSR_FS_BASE: + vmx_segment_cache_clear(vmx); + vmcs_writel(GUEST_FS_BASE, data); + break; + case MSR_GS_BASE: + vmx_segment_cache_clear(vmx); + vmcs_writel(GUEST_GS_BASE, data); + break; + case MSR_KERNEL_GS_BASE: + vmx_write_guest_kernel_gs_base(vmx, data); + break; +#endif + case MSR_IA32_SYSENTER_CS: + if (is_guest_mode(vcpu)) + get_vmcs12(vcpu)->guest_sysenter_cs = data; + vmcs_write32(GUEST_SYSENTER_CS, data); + break; + case MSR_IA32_SYSENTER_EIP: + if (is_guest_mode(vcpu)) + get_vmcs12(vcpu)->guest_sysenter_eip = data; + vmcs_writel(GUEST_SYSENTER_EIP, data); + break; + case MSR_IA32_SYSENTER_ESP: + if (is_guest_mode(vcpu)) + get_vmcs12(vcpu)->guest_sysenter_esp = data; + vmcs_writel(GUEST_SYSENTER_ESP, data); + break; + case MSR_IA32_DEBUGCTLMSR: + if (is_guest_mode(vcpu) && get_vmcs12(vcpu)->vm_exit_controls & + VM_EXIT_SAVE_DEBUG_CONTROLS) + get_vmcs12(vcpu)->guest_ia32_debugctl = data; + + ret = kvm_set_msr_common(vcpu, msr_info); + break; + + case MSR_IA32_BNDCFGS: + if (!kvm_mpx_supported() || + (!msr_info->host_initiated && + !guest_cpuid_has(vcpu, X86_FEATURE_MPX))) + return 1; + if (is_noncanonical_address(data & PAGE_MASK, vcpu) || + (data & MSR_IA32_BNDCFGS_RSVD)) + return 1; + vmcs_write64(GUEST_BNDCFGS, data); + break; + case MSR_IA32_UMWAIT_CONTROL: + if (!msr_info->host_initiated && !vmx_has_waitpkg(vmx)) + return 1; + + /* The reserved bit 1 and non-32 bit [63:32] should be zero */ + if (data & (BIT_ULL(1) | GENMASK_ULL(63, 32))) + return 1; + + vmx->msr_ia32_umwait_control = data; + break; + case MSR_IA32_SPEC_CTRL: + if (!msr_info->host_initiated && + !guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL)) + return 1; + + /* The STIBP bit doesn't fault even if it's not advertised */ + if (data & ~(SPEC_CTRL_IBRS | SPEC_CTRL_STIBP | SPEC_CTRL_SSBD)) + return 1; + + vmx->spec_ctrl = data; + + if (!data) + break; + + /* + * For non-nested: + * When it's written (to non-zero) for the first time, pass + * it through. + * + * For nested: + * The handling of the MSR bitmap for L2 guests is done in + * nested_vmx_prepare_msr_bitmap. We should not touch the + * vmcs02.msr_bitmap here since it gets completely overwritten + * in the merging. We update the vmcs01 here for L1 as well + * since it will end up touching the MSR anyway now. + */ + vmx_disable_intercept_for_msr(vmx->vmcs01.msr_bitmap, + MSR_IA32_SPEC_CTRL, + MSR_TYPE_RW); + break; + case MSR_IA32_TSX_CTRL: + if (!msr_info->host_initiated && + !(vcpu->arch.arch_capabilities & ARCH_CAP_TSX_CTRL_MSR)) + return 1; + if (data & ~(TSX_CTRL_RTM_DISABLE | TSX_CTRL_CPUID_CLEAR)) + return 1; + goto find_shared_msr; + case MSR_IA32_PRED_CMD: + if (!msr_info->host_initiated && + !guest_cpuid_has(vcpu, X86_FEATURE_SPEC_CTRL)) + return 1; + + if (data & ~PRED_CMD_IBPB) + return 1; + + if (!data) + break; + + wrmsrl(MSR_IA32_PRED_CMD, PRED_CMD_IBPB); + + /* + * For non-nested: + * When it's written (to non-zero) for the first time, pass + * it through. + * + * For nested: + * The handling of the MSR bitmap for L2 guests is done in + * nested_vmx_prepare_msr_bitmap. We should not touch the + * vmcs02.msr_bitmap here since it gets completely overwritten + * in the merging. + */ + vmx_disable_intercept_for_msr(vmx->vmcs01.msr_bitmap, MSR_IA32_PRED_CMD, + MSR_TYPE_W); + break; + case MSR_IA32_CR_PAT: + if (!kvm_pat_valid(data)) + return 1; + + if (is_guest_mode(vcpu) && + get_vmcs12(vcpu)->vm_exit_controls & VM_EXIT_SAVE_IA32_PAT) + get_vmcs12(vcpu)->guest_ia32_pat = data; + + if (vmcs_config.vmentry_ctrl & VM_ENTRY_LOAD_IA32_PAT) { + vmcs_write64(GUEST_IA32_PAT, data); + vcpu->arch.pat = data; + break; + } + ret = kvm_set_msr_common(vcpu, msr_info); + break; + case MSR_IA32_TSC_ADJUST: + ret = kvm_set_msr_common(vcpu, msr_info); + break; + case MSR_IA32_MCG_EXT_CTL: + if ((!msr_info->host_initiated && + !(to_vmx(vcpu)->msr_ia32_feature_control & + FEATURE_CONTROL_LMCE)) || + (data & ~MCG_EXT_CTL_LMCE_EN)) + return 1; + vcpu->arch.mcg_ext_ctl = data; + break; + case MSR_IA32_FEATURE_CONTROL: + if (!vmx_feature_control_msr_valid(vcpu, data) || + (to_vmx(vcpu)->msr_ia32_feature_control & + FEATURE_CONTROL_LOCKED && !msr_info->host_initiated)) + return 1; + vmx->msr_ia32_feature_control = data; + if (msr_info->host_initiated && data == 0) + vmx_leave_nested(vcpu); + break; + case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC: + if (!msr_info->host_initiated) + return 1; /* they are read-only */ + if (!nested_vmx_allowed(vcpu)) + return 1; + return vmx_set_vmx_msr(vcpu, msr_index, data); + case MSR_IA32_RTIT_CTL: + if ((pt_mode != PT_MODE_HOST_GUEST) || + vmx_rtit_ctl_check(vcpu, data) || + vmx->nested.vmxon) + return 1; + vmcs_write64(GUEST_IA32_RTIT_CTL, data); + vmx->pt_desc.guest.ctl = data; + pt_update_intercept_for_msr(vmx); + break; + case MSR_IA32_RTIT_STATUS: + if ((pt_mode != PT_MODE_HOST_GUEST) || + (vmx->pt_desc.guest.ctl & RTIT_CTL_TRACEEN) || + (data & MSR_IA32_RTIT_STATUS_MASK)) + return 1; + vmx->pt_desc.guest.status = data; + break; + case MSR_IA32_RTIT_CR3_MATCH: + if ((pt_mode != PT_MODE_HOST_GUEST) || + (vmx->pt_desc.guest.ctl & RTIT_CTL_TRACEEN) || + !intel_pt_validate_cap(vmx->pt_desc.caps, + PT_CAP_cr3_filtering)) + return 1; + vmx->pt_desc.guest.cr3_match = data; + break; + case MSR_IA32_RTIT_OUTPUT_BASE: + if ((pt_mode != PT_MODE_HOST_GUEST) || + (vmx->pt_desc.guest.ctl & RTIT_CTL_TRACEEN) || + (!intel_pt_validate_cap(vmx->pt_desc.caps, + PT_CAP_topa_output) && + !intel_pt_validate_cap(vmx->pt_desc.caps, + PT_CAP_single_range_output)) || + (data & MSR_IA32_RTIT_OUTPUT_BASE_MASK)) + return 1; + vmx->pt_desc.guest.output_base = data; + break; + case MSR_IA32_RTIT_OUTPUT_MASK: + if ((pt_mode != PT_MODE_HOST_GUEST) || + (vmx->pt_desc.guest.ctl & RTIT_CTL_TRACEEN) || + (!intel_pt_validate_cap(vmx->pt_desc.caps, + PT_CAP_topa_output) && + !intel_pt_validate_cap(vmx->pt_desc.caps, + PT_CAP_single_range_output))) + return 1; + vmx->pt_desc.guest.output_mask = data; + break; + case MSR_IA32_RTIT_ADDR0_A ... MSR_IA32_RTIT_ADDR3_B: + index = msr_info->index - MSR_IA32_RTIT_ADDR0_A; + if ((pt_mode != PT_MODE_HOST_GUEST) || + (vmx->pt_desc.guest.ctl & RTIT_CTL_TRACEEN) || + (index >= 2 * intel_pt_validate_cap(vmx->pt_desc.caps, + PT_CAP_num_address_ranges))) + return 1; + if (is_noncanonical_address(data, vcpu)) + return 1; + if (index % 2) + vmx->pt_desc.guest.addr_b[index / 2] = data; + else + vmx->pt_desc.guest.addr_a[index / 2] = data; + break; + case MSR_TSC_AUX: + if (!msr_info->host_initiated && + !guest_cpuid_has(vcpu, X86_FEATURE_RDTSCP)) + return 1; + /* Check reserved bit, higher 32 bits should be zero */ + if ((data >> 32) != 0) + return 1; + goto find_shared_msr; + + default: + find_shared_msr: + msr = find_msr_entry(vmx, msr_index); + if (msr) + ret = vmx_set_guest_msr(vmx, msr, data); + else + ret = kvm_set_msr_common(vcpu, msr_info); + } + + return ret; +} + +static void vmx_cache_reg(struct kvm_vcpu *vcpu, enum kvm_reg reg) +{ + kvm_register_mark_available(vcpu, reg); + + switch (reg) { + case VCPU_REGS_RSP: + vcpu->arch.regs[VCPU_REGS_RSP] = vmcs_readl(GUEST_RSP); + break; + case VCPU_REGS_RIP: + vcpu->arch.regs[VCPU_REGS_RIP] = vmcs_readl(GUEST_RIP); + break; + case VCPU_EXREG_PDPTR: + if (enable_ept) + ept_save_pdptrs(vcpu); + break; + case VCPU_EXREG_CR3: + if (enable_unrestricted_guest || (enable_ept && is_paging(vcpu))) + vcpu->arch.cr3 = vmcs_readl(GUEST_CR3); + break; + default: + WARN_ON_ONCE(1); + break; + } +} + +static __init int cpu_has_kvm_support(void) +{ + return cpu_has_vmx(); +} + +static __init int vmx_disabled_by_bios(void) +{ + u64 msr; + + rdmsrl(MSR_IA32_FEATURE_CONTROL, msr); + if (msr & FEATURE_CONTROL_LOCKED) { + /* launched w/ TXT and VMX disabled */ + if (!(msr & FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX) + && tboot_enabled()) + return 1; + /* launched w/o TXT and VMX only enabled w/ TXT */ + if (!(msr & FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX) + && (msr & FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX) + && !tboot_enabled()) { + printk(KERN_WARNING "kvm: disable TXT in the BIOS or " + "activate TXT before enabling KVM\n"); + return 1; + } + /* launched w/o TXT and VMX disabled */ + if (!(msr & FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX) + && !tboot_enabled()) + return 1; + } + + return 0; +} + +static void kvm_cpu_vmxon(u64 addr) +{ + cr4_set_bits(X86_CR4_VMXE); + intel_pt_handle_vmx(1); + + asm volatile ("vmxon %0" : : "m"(addr)); +} + +static int hardware_enable(void) +{ + int cpu = raw_smp_processor_id(); + u64 phys_addr = __pa(per_cpu(vmxarea, cpu)); + u64 old, test_bits; + + if (cr4_read_shadow() & X86_CR4_VMXE) + return -EBUSY; + + /* + * This can happen if we hot-added a CPU but failed to allocate + * VP assist page for it. + */ + if (static_branch_unlikely(&enable_evmcs) && + !hv_get_vp_assist_page(cpu)) + return -EFAULT; + + INIT_LIST_HEAD(&per_cpu(loaded_vmcss_on_cpu, cpu)); + INIT_LIST_HEAD(&per_cpu(blocked_vcpu_on_cpu, cpu)); + spin_lock_init(&per_cpu(blocked_vcpu_on_cpu_lock, cpu)); + + /* + * Now we can enable the vmclear operation in kdump + * since the loaded_vmcss_on_cpu list on this cpu + * has been initialized. + * + * Though the cpu is not in VMX operation now, there + * is no problem to enable the vmclear operation + * for the loaded_vmcss_on_cpu list is empty! + */ + crash_enable_local_vmclear(cpu); + + rdmsrl(MSR_IA32_FEATURE_CONTROL, old); + + test_bits = FEATURE_CONTROL_LOCKED; + test_bits |= FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX; + if (tboot_enabled()) + test_bits |= FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX; + + if ((old & test_bits) != test_bits) { + /* enable and lock */ + wrmsrl(MSR_IA32_FEATURE_CONTROL, old | test_bits); + } + kvm_cpu_vmxon(phys_addr); + if (enable_ept) + ept_sync_global(); + + return 0; +} + +static void vmclear_local_loaded_vmcss(void) +{ + int cpu = raw_smp_processor_id(); + struct loaded_vmcs *v, *n; + + list_for_each_entry_safe(v, n, &per_cpu(loaded_vmcss_on_cpu, cpu), + loaded_vmcss_on_cpu_link) + __loaded_vmcs_clear(v); +} + + +/* Just like cpu_vmxoff(), but with the __kvm_handle_fault_on_reboot() + * tricks. + */ +static void kvm_cpu_vmxoff(void) +{ + asm volatile (__ex("vmxoff")); + + intel_pt_handle_vmx(0); + cr4_clear_bits(X86_CR4_VMXE); +} + +static void hardware_disable(void) +{ + vmclear_local_loaded_vmcss(); + kvm_cpu_vmxoff(); +} + +static __init int adjust_vmx_controls(u32 ctl_min, u32 ctl_opt, + u32 msr, u32 *result) +{ + u32 vmx_msr_low, vmx_msr_high; + u32 ctl = ctl_min | ctl_opt; + + rdmsr(msr, vmx_msr_low, vmx_msr_high); + + ctl &= vmx_msr_high; /* bit == 0 in high word ==> must be zero */ + ctl |= vmx_msr_low; /* bit == 1 in low word ==> must be one */ + + /* Ensure minimum (required) set of control bits are supported. */ + if (ctl_min & ~ctl) + return -EIO; + + *result = ctl; + return 0; +} + +static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf, + struct vmx_capability *vmx_cap) +{ + u32 vmx_msr_low, vmx_msr_high; + u32 min, opt, min2, opt2; + u32 _pin_based_exec_control = 0; + u32 _cpu_based_exec_control = 0; + u32 _cpu_based_2nd_exec_control = 0; + u32 _vmexit_control = 0; + u32 _vmentry_control = 0; + + memset(vmcs_conf, 0, sizeof(*vmcs_conf)); + min = CPU_BASED_HLT_EXITING | +#ifdef CONFIG_X86_64 + CPU_BASED_CR8_LOAD_EXITING | + CPU_BASED_CR8_STORE_EXITING | +#endif + CPU_BASED_CR3_LOAD_EXITING | + CPU_BASED_CR3_STORE_EXITING | + CPU_BASED_UNCOND_IO_EXITING | + CPU_BASED_MOV_DR_EXITING | + CPU_BASED_USE_TSC_OFFSETTING | + CPU_BASED_MWAIT_EXITING | + CPU_BASED_MONITOR_EXITING | + CPU_BASED_INVLPG_EXITING | + CPU_BASED_RDPMC_EXITING; + + opt = CPU_BASED_TPR_SHADOW | + CPU_BASED_USE_MSR_BITMAPS | + CPU_BASED_ACTIVATE_SECONDARY_CONTROLS; + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PROCBASED_CTLS, + &_cpu_based_exec_control) < 0) + return -EIO; +#ifdef CONFIG_X86_64 + if ((_cpu_based_exec_control & CPU_BASED_TPR_SHADOW)) + _cpu_based_exec_control &= ~CPU_BASED_CR8_LOAD_EXITING & + ~CPU_BASED_CR8_STORE_EXITING; +#endif + if (_cpu_based_exec_control & CPU_BASED_ACTIVATE_SECONDARY_CONTROLS) { + min2 = 0; + opt2 = SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES | + SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | + SECONDARY_EXEC_WBINVD_EXITING | + SECONDARY_EXEC_ENABLE_VPID | + SECONDARY_EXEC_ENABLE_EPT | + SECONDARY_EXEC_UNRESTRICTED_GUEST | + SECONDARY_EXEC_PAUSE_LOOP_EXITING | + SECONDARY_EXEC_DESC | + SECONDARY_EXEC_RDTSCP | + SECONDARY_EXEC_ENABLE_INVPCID | + SECONDARY_EXEC_APIC_REGISTER_VIRT | + SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY | + SECONDARY_EXEC_SHADOW_VMCS | + SECONDARY_EXEC_XSAVES | + SECONDARY_EXEC_RDSEED_EXITING | + SECONDARY_EXEC_RDRAND_EXITING | + SECONDARY_EXEC_ENABLE_PML | + SECONDARY_EXEC_TSC_SCALING | + SECONDARY_EXEC_ENABLE_USR_WAIT_PAUSE | + SECONDARY_EXEC_PT_USE_GPA | + SECONDARY_EXEC_PT_CONCEAL_VMX | + SECONDARY_EXEC_ENABLE_VMFUNC | + SECONDARY_EXEC_ENCLS_EXITING; + if (adjust_vmx_controls(min2, opt2, + MSR_IA32_VMX_PROCBASED_CTLS2, + &_cpu_based_2nd_exec_control) < 0) + return -EIO; + } +#ifndef CONFIG_X86_64 + if (!(_cpu_based_2nd_exec_control & + SECONDARY_EXEC_VIRTUALIZE_APIC_ACCESSES)) + _cpu_based_exec_control &= ~CPU_BASED_TPR_SHADOW; +#endif + + if (!(_cpu_based_exec_control & CPU_BASED_TPR_SHADOW)) + _cpu_based_2nd_exec_control &= ~( + SECONDARY_EXEC_APIC_REGISTER_VIRT | + SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE | + SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY); + + rdmsr_safe(MSR_IA32_VMX_EPT_VPID_CAP, + &vmx_cap->ept, &vmx_cap->vpid); + + if (_cpu_based_2nd_exec_control & SECONDARY_EXEC_ENABLE_EPT) { + /* CR3 accesses and invlpg don't need to cause VM Exits when EPT + enabled */ + _cpu_based_exec_control &= ~(CPU_BASED_CR3_LOAD_EXITING | + CPU_BASED_CR3_STORE_EXITING | + CPU_BASED_INVLPG_EXITING); + } else if (vmx_cap->ept) { + vmx_cap->ept = 0; + pr_warn_once("EPT CAP should not exist if not support " + "1-setting enable EPT VM-execution control\n"); + } + if (!(_cpu_based_2nd_exec_control & SECONDARY_EXEC_ENABLE_VPID) && + vmx_cap->vpid) { + vmx_cap->vpid = 0; + pr_warn_once("VPID CAP should not exist if not support " + "1-setting enable VPID VM-execution control\n"); + } + + min = VM_EXIT_SAVE_DEBUG_CONTROLS | VM_EXIT_ACK_INTR_ON_EXIT; +#ifdef CONFIG_X86_64 + min |= VM_EXIT_HOST_ADDR_SPACE_SIZE; +#endif + opt = VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL | + VM_EXIT_LOAD_IA32_PAT | + VM_EXIT_LOAD_IA32_EFER | + VM_EXIT_CLEAR_BNDCFGS | + VM_EXIT_PT_CONCEAL_PIP | + VM_EXIT_CLEAR_IA32_RTIT_CTL; + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_EXIT_CTLS, + &_vmexit_control) < 0) + return -EIO; + + min = PIN_BASED_EXT_INTR_MASK | PIN_BASED_NMI_EXITING; + opt = PIN_BASED_VIRTUAL_NMIS | PIN_BASED_POSTED_INTR | + PIN_BASED_VMX_PREEMPTION_TIMER; + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_PINBASED_CTLS, + &_pin_based_exec_control) < 0) + return -EIO; + + if (cpu_has_broken_vmx_preemption_timer()) + _pin_based_exec_control &= ~PIN_BASED_VMX_PREEMPTION_TIMER; + if (!(_cpu_based_2nd_exec_control & + SECONDARY_EXEC_VIRTUAL_INTR_DELIVERY)) + _pin_based_exec_control &= ~PIN_BASED_POSTED_INTR; + + min = VM_ENTRY_LOAD_DEBUG_CONTROLS; + opt = VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL | + VM_ENTRY_LOAD_IA32_PAT | + VM_ENTRY_LOAD_IA32_EFER | + VM_ENTRY_LOAD_BNDCFGS | + VM_ENTRY_PT_CONCEAL_PIP | + VM_ENTRY_LOAD_IA32_RTIT_CTL; + if (adjust_vmx_controls(min, opt, MSR_IA32_VMX_ENTRY_CTLS, + &_vmentry_control) < 0) + return -EIO; + + /* + * Some cpus support VM_{ENTRY,EXIT}_IA32_PERF_GLOBAL_CTRL but they + * can't be used due to an errata where VM Exit may incorrectly clear + * IA32_PERF_GLOBAL_CTRL[34:32]. Workaround the errata by using the + * MSR load mechanism to switch IA32_PERF_GLOBAL_CTRL. + */ + if (boot_cpu_data.x86 == 0x6) { + switch (boot_cpu_data.x86_model) { + case 26: /* AAK155 */ + case 30: /* AAP115 */ + case 37: /* AAT100 */ + case 44: /* BC86,AAY89,BD102 */ + case 46: /* BA97 */ + _vmentry_control &= ~VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL; + _vmexit_control &= ~VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL; + pr_warn_once("kvm: VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL " + "does not work properly. Using workaround\n"); + break; + default: + break; + } + } + + + rdmsr(MSR_IA32_VMX_BASIC, vmx_msr_low, vmx_msr_high); + + /* IA-32 SDM Vol 3B: VMCS size is never greater than 4kB. */ + if ((vmx_msr_high & 0x1fff) > PAGE_SIZE) + return -EIO; + +#ifdef CONFIG_X86_64 + /* IA-32 SDM Vol 3B: 64-bit CPUs always have VMX_BASIC_MSR[48]==0. */ + if (vmx_msr_high & (1u<<16)) + return -EIO; +#endif + + /* Require Write-Back (WB) memory type for VMCS accesses. */ + if (((vmx_msr_high >> 18) & 15) != 6) + return -EIO; + + vmcs_conf->size = vmx_msr_high & 0x1fff; + vmcs_conf->order = get_order(vmcs_conf->size); + vmcs_conf->basic_cap = vmx_msr_high & ~0x1fff; + + vmcs_conf->revision_id = vmx_msr_low; + + vmcs_conf->pin_based_exec_ctrl = _pin_based_exec_control; + vmcs_conf->cpu_based_exec_ctrl = _cpu_based_exec_control; + vmcs_conf->cpu_based_2nd_exec_ctrl = _cpu_based_2nd_exec_control; + vmcs_conf->vmexit_ctrl = _vmexit_control; + vmcs_conf->vmentry_ctrl = _vmentry_control; + + if (static_branch_unlikely(&enable_evmcs)) + evmcs_sanitize_exec_ctrls(vmcs_conf); + + return 0; +} + +struct vmcs *alloc_vmcs_cpu(bool shadow, int cpu, gfp_t flags) +{ + int node = cpu_to_node(cpu); + struct page *pages; + struct vmcs *vmcs; + + pages = __alloc_pages_node(node, flags, vmcs_config.order); + if (!pages) + return NULL; + vmcs = page_address(pages); + memset(vmcs, 0, vmcs_config.size); + + /* KVM supports Enlightened VMCS v1 only */ + if (static_branch_unlikely(&enable_evmcs)) + vmcs->hdr.revision_id = KVM_EVMCS_VERSION; + else + vmcs->hdr.revision_id = vmcs_config.revision_id; + + if (shadow) + vmcs->hdr.shadow_vmcs = 1; + return vmcs; +} + +void free_vmcs(struct vmcs *vmcs) +{ + free_pages((unsigned long)vmcs, vmcs_config.order); +} + +/* + * Free a VMCS, but before that VMCLEAR it on the CPU where it was last loaded + */ +void free_loaded_vmcs(struct loaded_vmcs *loaded_vmcs) +{ + if (!loaded_vmcs->vmcs) + return; + loaded_vmcs_clear(loaded_vmcs); + free_vmcs(loaded_vmcs->vmcs); + loaded_vmcs->vmcs = NULL; + if (loaded_vmcs->msr_bitmap) + free_page((unsigned long)loaded_vmcs->msr_bitmap); + WARN_ON(loaded_vmcs->shadow_vmcs != NULL); +} + +int alloc_loaded_vmcs(struct loaded_vmcs *loaded_vmcs) +{ + loaded_vmcs->vmcs = alloc_vmcs(false); + if (!loaded_vmcs->vmcs) + return -ENOMEM; + + loaded_vmcs->shadow_vmcs = NULL; + loaded_vmcs->hv_timer_soft_disabled = false; + loaded_vmcs_init(loaded_vmcs); + + if (cpu_has_vmx_msr_bitmap()) { + loaded_vmcs->msr_bitmap = (unsigned long *) + __get_free_page(GFP_KERNEL_ACCOUNT); + if (!loaded_vmcs->msr_bitmap) + goto out_vmcs; + memset(loaded_vmcs->msr_bitmap, 0xff, PAGE_SIZE); + + if (IS_ENABLED(CONFIG_HYPERV) && + static_branch_unlikely(&enable_evmcs) && + (ms_hyperv.nested_features & HV_X64_NESTED_MSR_BITMAP)) { + struct hv_enlightened_vmcs *evmcs = + (struct hv_enlightened_vmcs *)loaded_vmcs->vmcs; + + evmcs->hv_enlightenments_control.msr_bitmap = 1; + } + } + + memset(&loaded_vmcs->host_state, 0, sizeof(struct vmcs_host_state)); + memset(&loaded_vmcs->controls_shadow, 0, + sizeof(struct vmcs_controls_shadow)); + + return 0; + +out_vmcs: + free_loaded_vmcs(loaded_vmcs); + return -ENOMEM; +} + +static void free_kvm_area(void) +{ + int cpu; + + for_each_possible_cpu(cpu) { + free_vmcs(per_cpu(vmxarea, cpu)); + per_cpu(vmxarea, cpu) = NULL; + } +} + +static __init int alloc_kvm_area(void) +{ + int cpu; + + for_each_possible_cpu(cpu) { + struct vmcs *vmcs; + + vmcs = alloc_vmcs_cpu(false, cpu, GFP_KERNEL); + if (!vmcs) { + free_kvm_area(); + return -ENOMEM; + } + + /* + * When eVMCS is enabled, alloc_vmcs_cpu() sets + * vmcs->revision_id to KVM_EVMCS_VERSION instead of + * revision_id reported by MSR_IA32_VMX_BASIC. + * + * However, even though not explicitly documented by + * TLFS, VMXArea passed as VMXON argument should + * still be marked with revision_id reported by + * physical CPU. + */ + if (static_branch_unlikely(&enable_evmcs)) + vmcs->hdr.revision_id = vmcs_config.revision_id; + + per_cpu(vmxarea, cpu) = vmcs; + } + return 0; +} + +static void fix_pmode_seg(struct kvm_vcpu *vcpu, int seg, + struct kvm_segment *save) +{ + if (!emulate_invalid_guest_state) { + /* + * CS and SS RPL should be equal during guest entry according + * to VMX spec, but in reality it is not always so. Since vcpu + * is in the middle of the transition from real mode to + * protected mode it is safe to assume that RPL 0 is a good + * default value. + */ + if (seg == VCPU_SREG_CS || seg == VCPU_SREG_SS) + save->selector &= ~SEGMENT_RPL_MASK; + save->dpl = save->selector & SEGMENT_RPL_MASK; + save->s = 1; + } + vmx_set_segment(vcpu, save, seg); +} + +static void enter_pmode(struct kvm_vcpu *vcpu) +{ + unsigned long flags; + struct vcpu_vmx *vmx = to_vmx(vcpu); + + /* + * Update real mode segment cache. It may be not up-to-date if sement + * register was written while vcpu was in a guest mode. + */ + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_ES], VCPU_SREG_ES); + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_DS], VCPU_SREG_DS); + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_FS], VCPU_SREG_FS); + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_GS], VCPU_SREG_GS); + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_SS], VCPU_SREG_SS); + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_CS], VCPU_SREG_CS); + + vmx->rmode.vm86_active = 0; + + vmx_segment_cache_clear(vmx); + + vmx_set_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_TR], VCPU_SREG_TR); + + flags = vmcs_readl(GUEST_RFLAGS); + flags &= RMODE_GUEST_OWNED_EFLAGS_BITS; + flags |= vmx->rmode.save_rflags & ~RMODE_GUEST_OWNED_EFLAGS_BITS; + vmcs_writel(GUEST_RFLAGS, flags); + + vmcs_writel(GUEST_CR4, (vmcs_readl(GUEST_CR4) & ~X86_CR4_VME) | + (vmcs_readl(CR4_READ_SHADOW) & X86_CR4_VME)); + + update_exception_bitmap(vcpu); + + fix_pmode_seg(vcpu, VCPU_SREG_CS, &vmx->rmode.segs[VCPU_SREG_CS]); + fix_pmode_seg(vcpu, VCPU_SREG_SS, &vmx->rmode.segs[VCPU_SREG_SS]); + fix_pmode_seg(vcpu, VCPU_SREG_ES, &vmx->rmode.segs[VCPU_SREG_ES]); + fix_pmode_seg(vcpu, VCPU_SREG_DS, &vmx->rmode.segs[VCPU_SREG_DS]); + fix_pmode_seg(vcpu, VCPU_SREG_FS, &vmx->rmode.segs[VCPU_SREG_FS]); + fix_pmode_seg(vcpu, VCPU_SREG_GS, &vmx->rmode.segs[VCPU_SREG_GS]); +} + +static void fix_rmode_seg(int seg, struct kvm_segment *save) +{ + const struct kvm_vmx_segment_field *sf = &kvm_vmx_segment_fields[seg]; + struct kvm_segment var = *save; + + var.dpl = 0x3; + if (seg == VCPU_SREG_CS) + var.type = 0x3; + + if (!emulate_invalid_guest_state) { + var.selector = var.base >> 4; + var.base = var.base & 0xffff0; + var.limit = 0xffff; + var.g = 0; + var.db = 0; + var.present = 1; + var.s = 1; + var.l = 0; + var.unusable = 0; + var.type = 0x3; + var.avl = 0; + if (save->base & 0xf) + printk_once(KERN_WARNING "kvm: segment base is not " + "paragraph aligned when entering " + "protected mode (seg=%d)", seg); + } + + vmcs_write16(sf->selector, var.selector); + vmcs_writel(sf->base, var.base); + vmcs_write32(sf->limit, var.limit); + vmcs_write32(sf->ar_bytes, vmx_segment_access_rights(&var)); +} + +static void enter_rmode(struct kvm_vcpu *vcpu) +{ + unsigned long flags; + struct vcpu_vmx *vmx = to_vmx(vcpu); + struct kvm_vmx *kvm_vmx = to_kvm_vmx(vcpu->kvm); + + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_TR], VCPU_SREG_TR); + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_ES], VCPU_SREG_ES); + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_DS], VCPU_SREG_DS); + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_FS], VCPU_SREG_FS); + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_GS], VCPU_SREG_GS); + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_SS], VCPU_SREG_SS); + vmx_get_segment(vcpu, &vmx->rmode.segs[VCPU_SREG_CS], VCPU_SREG_CS); + + vmx->rmode.vm86_active = 1; + + /* + * Very old userspace does not call KVM_SET_TSS_ADDR before entering + * vcpu. Warn the user that an update is overdue. + */ + if (!kvm_vmx->tss_addr) + printk_once(KERN_WARNING "kvm: KVM_SET_TSS_ADDR need to be " + "called before entering vcpu\n"); + + vmx_segment_cache_clear(vmx); + + vmcs_writel(GUEST_TR_BASE, kvm_vmx->tss_addr); + vmcs_write32(GUEST_TR_LIMIT, RMODE_TSS_SIZE - 1); + vmcs_write32(GUEST_TR_AR_BYTES, 0x008b); + + flags = vmcs_readl(GUEST_RFLAGS); + vmx->rmode.save_rflags = flags; + + flags |= X86_EFLAGS_IOPL | X86_EFLAGS_VM; + + vmcs_writel(GUEST_RFLAGS, flags); + vmcs_writel(GUEST_CR4, vmcs_readl(GUEST_CR4) | X86_CR4_VME); + update_exception_bitmap(vcpu); + + fix_rmode_seg(VCPU_SREG_SS, &vmx->rmode.segs[VCPU_SREG_SS]); + fix_rmode_seg(VCPU_SREG_CS, &vmx->rmode.segs[VCPU_SREG_CS]); + fix_rmode_seg(VCPU_SREG_ES, &vmx->rmode.segs[VCPU_SREG_ES]); + fix_rmode_seg(VCPU_SREG_DS, &vmx->rmode.segs[VCPU_SREG_DS]); + fix_rmode_seg(VCPU_SREG_GS, &vmx->rmode.segs[VCPU_SREG_GS]); + fix_rmode_seg(VCPU_SREG_FS, &vmx->rmode.segs[VCPU_SREG_FS]); + + kvm_mmu_reset_context(vcpu); +} + +void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + struct shared_msr_entry *msr = find_msr_entry(vmx, MSR_EFER); + + if (!msr) + return; + + vcpu->arch.efer = efer; + if (efer & EFER_LMA) { + vm_entry_controls_setbit(to_vmx(vcpu), VM_ENTRY_IA32E_MODE); + msr->data = efer; + } else { + vm_entry_controls_clearbit(to_vmx(vcpu), VM_ENTRY_IA32E_MODE); + + msr->data = efer & ~EFER_LME; + } + setup_msrs(vmx); +} + +#ifdef CONFIG_X86_64 + +static void enter_lmode(struct kvm_vcpu *vcpu) +{ + u32 guest_tr_ar; + + vmx_segment_cache_clear(to_vmx(vcpu)); + + guest_tr_ar = vmcs_read32(GUEST_TR_AR_BYTES); + if ((guest_tr_ar & VMX_AR_TYPE_MASK) != VMX_AR_TYPE_BUSY_64_TSS) { + pr_debug_ratelimited("%s: tss fixup for long mode. \n", + __func__); + vmcs_write32(GUEST_TR_AR_BYTES, + (guest_tr_ar & ~VMX_AR_TYPE_MASK) + | VMX_AR_TYPE_BUSY_64_TSS); + } + vmx_set_efer(vcpu, vcpu->arch.efer | EFER_LMA); +} + +static void exit_lmode(struct kvm_vcpu *vcpu) +{ + vm_entry_controls_clearbit(to_vmx(vcpu), VM_ENTRY_IA32E_MODE); + vmx_set_efer(vcpu, vcpu->arch.efer & ~EFER_LMA); +} + +#endif + +static void vmx_flush_tlb_gva(struct kvm_vcpu *vcpu, gva_t addr) +{ + int vpid = to_vmx(vcpu)->vpid; + + if (!vpid_sync_vcpu_addr(vpid, addr)) + vpid_sync_context(vpid); + + /* + * If VPIDs are not supported or enabled, then the above is a no-op. + * But we don't really need a TLB flush in that case anyway, because + * each VM entry/exit includes an implicit flush when VPID is 0. + */ +} + +static void vmx_decache_cr0_guest_bits(struct kvm_vcpu *vcpu) +{ + ulong cr0_guest_owned_bits = vcpu->arch.cr0_guest_owned_bits; + + vcpu->arch.cr0 &= ~cr0_guest_owned_bits; + vcpu->arch.cr0 |= vmcs_readl(GUEST_CR0) & cr0_guest_owned_bits; +} + +static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu) +{ + ulong cr4_guest_owned_bits = vcpu->arch.cr4_guest_owned_bits; + + vcpu->arch.cr4 &= ~cr4_guest_owned_bits; + vcpu->arch.cr4 |= vmcs_readl(GUEST_CR4) & cr4_guest_owned_bits; +} + +static void ept_load_pdptrs(struct kvm_vcpu *vcpu) +{ + struct kvm_mmu *mmu = vcpu->arch.walk_mmu; + + if (!kvm_register_is_dirty(vcpu, VCPU_EXREG_PDPTR)) + return; + + if (is_pae_paging(vcpu)) { + vmcs_write64(GUEST_PDPTR0, mmu->pdptrs[0]); + vmcs_write64(GUEST_PDPTR1, mmu->pdptrs[1]); + vmcs_write64(GUEST_PDPTR2, mmu->pdptrs[2]); + vmcs_write64(GUEST_PDPTR3, mmu->pdptrs[3]); + } +} + +void ept_save_pdptrs(struct kvm_vcpu *vcpu) +{ + struct kvm_mmu *mmu = vcpu->arch.walk_mmu; + + if (is_pae_paging(vcpu)) { + mmu->pdptrs[0] = vmcs_read64(GUEST_PDPTR0); + mmu->pdptrs[1] = vmcs_read64(GUEST_PDPTR1); + mmu->pdptrs[2] = vmcs_read64(GUEST_PDPTR2); + mmu->pdptrs[3] = vmcs_read64(GUEST_PDPTR3); + } + + kvm_register_mark_dirty(vcpu, VCPU_EXREG_PDPTR); +} + +static void ept_update_paging_mode_cr0(unsigned long *hw_cr0, + unsigned long cr0, + struct kvm_vcpu *vcpu) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + + if (!kvm_register_is_available(vcpu, VCPU_EXREG_CR3)) + vmx_cache_reg(vcpu, VCPU_EXREG_CR3); + if (!(cr0 & X86_CR0_PG)) { + /* From paging/starting to nonpaging */ + exec_controls_setbit(vmx, CPU_BASED_CR3_LOAD_EXITING | + CPU_BASED_CR3_STORE_EXITING); + vcpu->arch.cr0 = cr0; + vmx_set_cr4(vcpu, kvm_read_cr4(vcpu)); + } else if (!is_paging(vcpu)) { + /* From nonpaging to paging */ + exec_controls_clearbit(vmx, CPU_BASED_CR3_LOAD_EXITING | + CPU_BASED_CR3_STORE_EXITING); + vcpu->arch.cr0 = cr0; + vmx_set_cr4(vcpu, kvm_read_cr4(vcpu)); + } + + if (!(cr0 & X86_CR0_WP)) + *hw_cr0 &= ~X86_CR0_WP; +} + +void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0) +{ + struct vcpu_vmx *vmx = to_vmx(vcpu); + unsigned long hw_cr0; + + hw_cr0 = (cr0 & ~KVM_VM_CR0_ALWAYS_OFF); + if (enable_unrestricted_guest) + hw_cr0 |= KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST; + else { + hw_cr0 |= KVM_VM_CR0_ALWAYS_ON; + + if (vmx->rmode.vm86_active && (cr0 & X86_CR0_PE)) + enter_pmode(vcpu); + + if (!vmx->rmode.vm86_active && !(cr0 & X86_CR0_PE)) + enter_rmode(vcpu); + } + +#ifdef CONFIG_X86_64 + if (vcpu->arch.efer & EFER_LME) { + if (!is_paging(vcpu) && (cr0 & X86_CR0_PG)) + enter_lmode(vcpu); + if (is_paging(vcpu) && !(cr0 & X86_CR0_PG)) + exit_lmode(vcpu); + } +#endif + + if (enable_ept && !enable_unrestricted_guest) + ept_update_paging_mode_cr0(&hw_cr0, cr0, vcpu); + + vmcs_writel(CR0_READ_SHADOW, cr0); + vmcs_writel(GUEST_CR0, hw_cr0); + vcpu->arch.cr0 = cr0; + + /* depends on vcpu->arch.cr0 to be set to a new value */ + vmx->emulation_required = emulation_required(vcpu); +} + +static int get_ept_level(struct kvm_vcpu *vcpu) +{ + if (cpu_has_vmx_ept_5levels() && (cpuid_maxphyaddr(vcpu) > 48)) + return 5; + return 4; +} + +u64 construct_eptp(struct kvm_vcpu *vcpu, unsigned long root_hpa) +{ + u64 eptp = VMX_EPTP_MT_WB; + + eptp |= (get_ept_level(vcpu) == 5) ? VMX_EPTP_PWL_5 : VMX_EPTP_PWL_4; + + if (enable_ept_ad_bits && + (!is_guest_mode(vcpu) || nested_ept_ad_enabled(vcpu))) + eptp |= VMX_EPTP_AD_ENABLE_BIT; + eptp |= (root_hpa & PAGE_MASK); + + return eptp; +} + +void vmx_set_cr3(struct kvm_vcpu *vcpu, unsigned long cr3) +{ + struct kvm *kvm = vcpu->kvm; + bool update_guest_cr3 = true; + unsigned long guest_cr3; + u64 eptp; + + guest_cr3 = cr3; + if (enable_ept) { + eptp = construct_eptp(vcpu, cr3); + vmcs_write64(EPT_POINTER, eptp);
Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Signature · 1 line
2.20.1
Part of the diff is not shown here. View the raw message.
Greg Kroah-Hartman
maintainerPATCH 157/173 tools/power/acpi: fix compilation error
In reply to Greg Kroah-HartmanFrom: Zhengyuan Liu <[email protected]>
commit 1985f8c7f9a42a651a9750d6fcadc74336d182df upstream.
If we compile tools/acpi target in the top source directory, we'd get a compilation error showing as bellow:
# make tools/acpi DESCEND power/acpi DESCEND tools/acpidbg CC tools/acpidbg/acpidbg.o Assembler messages: Fatal error: can't create /home/lzy/kernel-upstream/power/acpi/\ tools/acpidbg/acpidbg.o: No such file or directory ../../Makefile.rules:26: recipe for target '/home/lzy/kernel-upstream/\ power/acpi/tools/acpidbg/acpidbg.o' failed make[3]: *** [/home/lzy/kernel-upstream//power/acpi/tools/acpidbg/\ acpidbg.o] Error 1 Makefile:19: recipe for target 'acpidbg' failed make[2]: *** [acpidbg] Error 2 Makefile:54: recipe for target 'acpi' failed make[1]: *** [acpi] Error 2 Makefile:1607: recipe for target 'tools/acpi' failed make: *** [tools/acpi] Error 2
--- tools/power/acpi/Makefile.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/power/acpi/Makefile.config +1 -1
@@ -18,7 +18,7 @@ include $(srctree)/../../scripts/Makefil OUTPUT=$(srctree)/ ifeq ("$(origin O)", "command line") - OUTPUT := $(O)/power/acpi/ + OUTPUT := $(O)/tools/power/acpi/ endif #$(info Determined 'OUTPUT' to be $(OUTPUT))
Greg Kroah-Hartman
maintainerPATCH 156/173 ARM: dts: at91: sama5d3: define clock rate range for tcb1
In reply to Greg Kroah-HartmanFrom: Alexandre Belloni <[email protected]>
commit a7e0f3fc01df4b1b7077df777c37feae8c9e8b6d upstream.
The clock rate range for the TCB1 clock is missing. define it in the device tree.
--- arch/arm/boot/dts/sama5d3_tcb1.dtsi | 1 + 1 file changed, 1 insertion(+)
arch/arm/boot/dts/sama5d3_tcb1.dtsi +1 -0
@@ -23,6 +23,7 @@ tcb1_clk: tcb1_clk { #clock-cells = <0>; reg = <27>; + atmel,clk-output-range = <0 166000000>; }; }; };
Greg Kroah-Hartman
maintainerPATCH 154/173 platform/x86: intel_mid_powerbtn: Take a copy of ddata
In reply to Greg Kroah-HartmanFrom: Mika Westerberg <[email protected]>
commit 5e0c94d3aeeecc68c573033f08d9678fecf253bd upstream.
The driver gets driver_data from memory that is marked as const (which is probably put to read-only memory) and it then modifies it. This likely causes some sort of fault to happen.
Fix this by taking a copy of the structure.
--- drivers/platform/x86/intel_mid_powerbtn.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/platform/x86/intel_mid_powerbtn.c +3 -2
@@ -158,9 +158,10 @@ static int mid_pb_probe(struct platform_input_set_capability (input,EV_KEY ,KEY_POWER ); - ddata = (struct mid_pb_ddata *)id->driver_data; + ddata =devm_kmemdup (&pdev->dev, (void *)id->driver_data, +sizeof (*ddata),GFP_KERNEL );if (!ddata) -return -ENODATA ; +return -ENOMEM ; ddata->dev = &pdev->dev; ddata->irq = irq;
Greg Kroah-Hartman
maintainerPATCH 155/173 ARM: dts: at91: sama5d3: fix maximum peripheral clock rates
In reply to Greg Kroah-HartmanFrom: Alexandre Belloni <[email protected]>
commit ee0aa926ddb0bd8ba59e33e3803b3b5804e3f5da upstream.
Currently the maximum rate for peripheral clock is calculated based on a typical 133MHz MCK. The maximum frequency is defined in the datasheet as a ratio to MCK. Some sama5d3 platforms are using a 166MHz MCK. Update the device trees to match the maximum rate based on 166MHz.
--- arch/arm/boot/dts/sama5d3.dtsi | 28 ++++++++++++++-------------- arch/arm/boot/dts/sama5d3_can.dtsi | 4 ++-- arch/arm/boot/dts/sama5d3_uart.dtsi | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-)
arch/arm/boot/dts/sama5d3.dtsi +14 -14
@@ -1185,49 +1185,49 @@ usart0_clk: usart0_clk { #clock-cells = <0>; reg = <12>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; usart1_clk: usart1_clk { #clock-cells = <0>; reg = <13>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; usart2_clk: usart2_clk { #clock-cells = <0>; reg = <14>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; usart3_clk: usart3_clk { #clock-cells = <0>; reg = <15>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; uart0_clk: uart0_clk { #clock-cells = <0>; reg = <16>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; twi0_clk: twi0_clk { reg = <18>; #clock-cells = <0>; - atmel,clk-output-range = <0 16625000>; + atmel,clk-output-range = <0 41500000>; }; twi1_clk: twi1_clk { #clock-cells = <0>; reg = <19>; - atmel,clk-output-range = <0 16625000>; + atmel,clk-output-range = <0 41500000>; }; twi2_clk: twi2_clk { #clock-cells = <0>; reg = <20>; - atmel,clk-output-range = <0 16625000>; + atmel,clk-output-range = <0 41500000>; }; mci0_clk: mci0_clk {
@@ -1243,19 +1243,19 @@ spi0_clk: spi0_clk { #clock-cells = <0>; reg = <24>; - atmel,clk-output-range = <0 133000000>; + atmel,clk-output-range = <0 166000000>; }; spi1_clk: spi1_clk { #clock-cells = <0>; reg = <25>; - atmel,clk-output-range = <0 133000000>; + atmel,clk-output-range = <0 166000000>; }; tcb0_clk: tcb0_clk { #clock-cells = <0>; reg = <26>; - atmel,clk-output-range = <0 133000000>; + atmel,clk-output-range = <0 166000000>; }; pwm_clk: pwm_clk {
@@ -1266,7 +1266,7 @@ adc_clk: adc_clk { #clock-cells = <0>; reg = <29>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; dma0_clk: dma0_clk {
@@ -1297,13 +1297,13 @@ ssc0_clk: ssc0_clk { #clock-cells = <0>; reg = <38>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; ssc1_clk: ssc1_clk { #clock-cells = <0>; reg = <39>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; sha_clk: sha_clk {
arch/arm/boot/dts/sama5d3_can.dtsi +2 -2
@@ -37,13 +37,13 @@ can0_clk: can0_clk { #clock-cells = <0>; reg = <40>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; can1_clk: can1_clk { #clock-cells = <0>; reg = <41>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; }; };
arch/arm/boot/dts/sama5d3_uart.dtsi +2 -2
@@ -42,13 +42,13 @@ uart0_clk: uart0_clk { #clock-cells = <0>; reg = <16>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; uart1_clk: uart1_clk { #clock-cells = <0>; reg = <17>; - atmel,clk-output-range = <0 66000000>; + atmel,clk-output-range = <0 83000000>; }; }; };
Greg Kroah-Hartman
maintainerPATCH 145/173 PCI/switchtec: Fix vep_vector_number ioread width
In reply to Greg Kroah-HartmanFrom: Logan Gunthorpe <[email protected]>
commit 9375646b4cf03aee81bc6c305aa18cc80b682796 upstream.
vep_vector_number is actually a 16 bit register which should be read with ioread16() instead of ioread32().
--- drivers/pci/switch/switchtec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pci/switch/switchtec.c +1 -1
@@ -1399,7 +1399,7 @@ static int switchtec_init_isr(struct swiif (nvecs <0 )return nvecs; - event_irq =ioread32 (&stdev->mmio_part_cfg->vep_vector_number); + event_irq =ioread16 (&stdev->mmio_part_cfg->vep_vector_number);if (event_irq <0 || event_irq >= nvecs)return -EFAULT ;
Greg Kroah-Hartman
maintainerPATCH 134/173 KVM: Use vcpu-specific gva->hva translation when querying host page size
In reply to Greg Kroah-HartmanFrom: Sean Christopherson <[email protected]>
[ Upstream commit f9b84e19221efc5f493156ee0329df3142085f28 ]
Use kvm_vcpu_gfn_to_hva() when retrieving the host page size so that the correct set of memslots is used when handling x86 page faults in SMM.
--- arch/x86/kvm/mmu.c | 6 +++--- include/linux/kvm_host.h | 2 +- virt/kvm/kvm_main.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-)
arch/x86/kvm/mmu.c +3 -3
@@ -1165,12 +1165,12 @@ static bool mmu_gfn_lpage_is_disallowed(struct kvm_vcpu *vcpu, gfn_t gfn,return __mmu_gfn_lpage_is_disallowed (gfn, level, slot); } -static int host_mapping_level (struct kvm *kvm,gfn_t gfn) +static int host_mapping_level (struct kvm_vcpu *vcpu,gfn_t gfn) {unsigned long page_size;int i, ret =0 ; - page_size =kvm_host_page_size (kvm, gfn); + page_size =kvm_host_page_size (vcpu, gfn);for (i =PT_PAGE_TABLE_LEVEL ; i <=PT_MAX_HUGEPAGE_LEVEL ; ++i) {if (page_size >=KVM_HPAGE_SIZE (i))
@@ -1220,7 +1220,7 @@ static int mapping_level(struct kvm_vcpu *vcpu, gfn_t large_gfn,if (unlikely (*force_pt_level))return PT_PAGE_TABLE_LEVEL ; - host_level =host_mapping_level (vcpu->kvm, large_gfn); + host_level =host_mapping_level (vcpu, large_gfn);if (host_level ==PT_PAGE_TABLE_LEVEL )return host_level;
include/linux/kvm_host.h +1 -1
@@ -695,7 +695,7 @@ int kvm_clear_guest_page(struct kvm *kvm, gfn_t gfn, int offset, int len);int kvm_clear_guest (struct kvm *kvm,gpa_t gpa,unsigned long len);struct kvm_memory_slot *gfn_to_memslot (struct kvm *kvm,gfn_t gfn);bool kvm_is_visible_gfn (struct kvm *kvm,gfn_t gfn); -unsigned long kvm_host_page_size (struct kvm *kvm,gfn_t gfn); +unsigned long kvm_host_page_size (struct kvm_vcpu *vcpu,gfn_t gfn);void mark_page_dirty (struct kvm *kvm,gfn_t gfn);struct kvm_memslots *kvm_vcpu_memslots (struct kvm_vcpu *vcpu);
virt/kvm/kvm_main.c +2 -2
@@ -1277,14 +1277,14 @@ bool kvm_is_visible_gfn(struct kvm *kvm, gfn_t gfn) }EXPORT_SYMBOL_GPL (kvm_is_visible_gfn); -unsigned long kvm_host_page_size (struct kvm *kvm,gfn_t gfn) +unsigned long kvm_host_page_size (struct kvm_vcpu *vcpu,gfn_t gfn) {struct vm_area_struct *vma;unsigned long addr, size; size =PAGE_SIZE ; - addr =gfn_to_hva (kvm, gfn); + addr =kvm_vcpu_gfn_to_hva (vcpu, gfn);if (kvm_is_error_hva (addr))return PAGE_SIZE ;
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 135/173 KVM: Play nice with read-only memslots when querying host page size
In reply to Greg Kroah-HartmanFrom: Sean Christopherson <[email protected]>
[ Upstream commit 42cde48b2d39772dba47e680781a32a6c4b7dc33 ]
Avoid the "writable" check in __gfn_to_hva_many(), which will always fail on read-only memslots due to gfn_to_hva() assuming writes. Functionally, this allows x86 to create large mappings for read-only memslots that are backed by HugeTLB mappings.
Note, the changelog for commit 05da45583de9 ("KVM: MMU: large page support") states "If the largepage contains write-protected pages, a large pte is not used.", but "write-protected" refers to pages that are temporarily read-only, e.g. read-only memslots didn't even exist at the time.
--- virt/kvm/kvm_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
virt/kvm/kvm_main.c +1 -1
@@ -1284,7 +1284,7 @@ unsigned long kvm_host_page_size(struct kvm_vcpu *vcpu, gfn_t gfn) size =PAGE_SIZE ; - addr =kvm_vcpu_gfn_to_hva (vcpu, gfn); + addr =kvm_vcpu_gfn_to_hva_prot (vcpu, gfn,NULL );if (kvm_is_error_hva (addr))return PAGE_SIZE ;
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 133/173 KVM: nVMX: vmread should not set rflags to specify success in case of #PF
In reply to Greg Kroah-HartmanFrom: Miaohe Lin <[email protected]>
[ Upstream commit a4d956b9390418623ae5d07933e2679c68b6f83c ]
In case writing to vmread destination operand result in a #PF, vmread should not call nested_vmx_succeed() to set rflags to specify success. Similar to as done in VMPTRST (See handle_vmptrst()).
--- arch/x86/kvm/vmx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
arch/x86/kvm/vmx.c +3 -1
@@ -8014,8 +8014,10 @@ static int handle_vmread(struct kvm_vcpu *vcpu)/* _system ok, nested_vmx_check_permission has verified cpl=0 */ if (kvm_write_guest_virt_system (vcpu, gva, &field_value, (is_long_mode (vcpu) ?8 :4 ), - &e)) + &e)) {kvm_inject_page_fault (vcpu, &e); +return 1 ; + } }nested_vmx_succeed (vcpu);
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 130/173 KVM: x86: Fix potential put_fpu() w/o load_fpu() on MPX platform
In reply to Greg Kroah-HartmanFrom: Sean Christopherson <[email protected]>
[ Upstream commit f958bd2314d117f8c29f4821401bc1925bc2e5ef ]
Unlike most state managed by XSAVE, MPX is initialized to zero on INIT. Because INITs are usually recognized in the context of a VCPU_RUN call, kvm_vcpu_reset() puts the guest's FPU so that the FPU state is resident in memory, zeros the MPX state, and reloads FPU state to hardware. But, in the unlikely event that an INIT is recognized during kvm_arch_vcpu_ioctl_get_mpstate() via kvm_apic_accept_events(), kvm_vcpu_reset() will call kvm_put_guest_fpu() without a preceding kvm_load_guest_fpu() and corrupt the guest's FPU state (and possibly userspace's FPU state as well).
Given that MPX is being removed from the kernel[*], fix the bug with the simple-but-ugly approach of loading the guest's FPU during KVM_GET_MP_STATE.
[*] See commit f240652b6032b ("x86/mpx: Remove MPX APIs").
--- arch/x86/kvm/x86.c | 5 +++++ 1 file changed, 5 insertions(+)
arch/x86/kvm/x86.c +5 -0
@@ -7677,6 +7677,9 @@ int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu,int kvm_arch_vcpu_ioctl_get_mpstate (struct kvm_vcpu *vcpu,struct kvm_mp_state *mp_state) { +if (kvm_mpx_supported ()) +kvm_load_guest_fpu (vcpu); +kvm_apic_accept_events (vcpu);if (vcpu->arch.mp_state ==KVM_MP_STATE_HALTED && vcpu->arch.pv.pv_unhalted)
@@ -7684,6 +7687,8 @@ int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,else mp_state->mp_state = vcpu->arch.mp_state; +if (kvm_mpx_supported ()) +kvm_put_guest_fpu (vcpu);return 0 ; }
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 131/173 KVM: x86/mmu: Apply max PA check for MMIO sptes to 32-bit KVM
In reply to Greg Kroah-HartmanFrom: Sean Christopherson <[email protected]>
[ Upstream commit e30a7d623dccdb3f880fbcad980b0cb589a1da45 ]
Remove the bogus 64-bit only condition from the check that disables MMIO spte optimization when the system supports the max PA, i.e. doesn't have any reserved PA bits. 32-bit KVM always uses PAE paging for the shadow MMU, and per Intel's SDM:
PAE paging translates 32-bit linear addresses to 52-bit physical addresses.
The kernel's restrictions on max physical addresses are limits on how much memory the kernel can reasonably use, not what physical addresses are supported by hardware.
--- arch/x86/kvm/x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kvm/x86.c +1 -1
@@ -6314,7 +6314,7 @@ static void kvm_set_mmio_spte_mask(void)* If reserved bit is not supported, clear the present bit to disable * mmio page fault. */ -if (IS_ENABLED (CONFIG_X86_64 ) && maxphyaddr ==52 ) +if (maxphyaddr ==52 ) mask &= ~1ull ;kvm_mmu_set_mmio_spte_mask (mask, mask);
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 129/173 btrfs: flush write bio if we loop in extent_write_cache_pages
In reply to Greg Kroah-HartmanFrom: Josef Bacik <[email protected]>
[ Upstream commit 96bf313ecb33567af4cb53928b0c951254a02759 ]
There exists a deadlock with range_cyclic that has existed forever. If we loop around with a bio already built we could deadlock with a writer who has the page locked that we're attempting to write but is waiting on a page in our bio to be written out. The task traces are as follows
PID: 1329874 TASK: ffff889ebcdf3800 CPU: 33 COMMAND: "kworker/u113:5"
#0 [ffffc900297bb658] __schedule at ffffffff81a4c33f
#1 [ffffc900297bb6e0] schedule at ffffffff81a4c6e3
#2 [ffffc900297bb6f8] io_schedule at ffffffff81a4ca42
#3 [ffffc900297bb708] __lock_page at ffffffff811f145b
#4 [ffffc900297bb798] __process_pages_contig at ffffffff814bc502 #5 [ffffc900297bb8c8] lock_delalloc_pages at ffffffff814bc684 #6 [ffffc900297bb900] find_lock_delalloc_range at ffffffff814be9ff #7 [ffffc900297bb9a0] writepage_delalloc at ffffffff814bebd0 #8 [ffffc900297bba18] __extent_writepage at ffffffff814bfbf2 #9 [ffffc900297bba98] extent_write_cache_pages at ffffffff814bffbd
PID: 2167901 TASK: ffff889dc6a59c00 CPU: 14 COMMAND:
"aio-dio-invalid"
#0 [ffffc9003b50bb18] __schedule at ffffffff81a4c33f #1 [ffffc9003b50bba0] schedule at ffffffff81a4c6e3 #2 [ffffc9003b50bbb8] io_schedule at ffffffff81a4ca42 #3 [ffffc9003b50bbc8] wait_on_page_bit at ffffffff811f24d6 #4 [ffffc9003b50bc60] prepare_pages at ffffffff814b05a7 #5 [ffffc9003b50bcd8] btrfs_buffered_write at ffffffff814b1359 #6 [ffffc9003b50bdb0] btrfs_file_write_iter at ffffffff814b5933 #7 [ffffc9003b50be38] new_sync_write at ffffffff8128f6a8 #8 [ffffc9003b50bec8] vfs_write at ffffffff81292b9d #9 [ffffc9003b50bf00] ksys_pwrite64 at ffffffff81293032
I used drgn to find the respective pages we were stuck on
page_entry.page 0xffffea00fbfc7500 index 8148 bit 15 pid 2167901 page_entry.page 0xffffea00f9bb7400 index 7680 bit 0 pid 1329874
As you can see the kworker is waiting for bit 0 (PG_locked) on index 7680, and aio-dio-invalid is waiting for bit 15 (PG_writeback) on index 8148. aio-dio-invalid has 7680, and the kworker epd looks like the following
crash> struct extent_page_data ffffc900297bbbb0
struct extent_page_data {
bio = 0xffff889f747ed830,
tree = 0xffff889eed6ba448,
extent_locked = 0,
sync_io = 0
}Probably worth mentioning as well that it waits for writeback of the page to complete while holding a lock on it (at prepare_pages()).
Using drgn I walked the bio pages looking for page 0xffffea00fbfc7500 which is the one we're waiting for writeback on
bio = Object(prog, 'struct bio', address=0xffff889f747ed830) for i in range(0, bio.bi_vcnt.value_()):
bv = bio.bi_io_vec[i]
if bv.bv_page.value_() == 0xffffea00fbfc7500:
print("FOUND IT")which validated what I suspected.
The fix for this is simple, flush the epd before we loop back around to the beginning of the file during writeout.
--- fs/btrfs/extent_io.c | 8 ++++++++ 1 file changed, 8 insertions(+)
fs/btrfs/extent_io.c +8 -0
@@ -4048,6 +4048,14 @@ static int extent_write_cache_pages(struct address_space *mapping,*/ scanned =1 ; index =0 ; + +/* +* If we're looping we could run into a page that is locked by a +* writer and that writer could be waiting on writeback for a +* page in our current bio, and thus deadlock, so flush the +* write bio here. +*/ +flush_write_bio (data); goto retry; }
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 142/173 hv_sock: Remove the accept port restriction
In reply to Greg Kroah-HartmanFrom: Sunil Muthuswamy <[email protected]>
[ Upstream commit c742c59e1fbd022b64d91aa9a0092b3a699d653c ]
Currently, hv_sock restricts the port the guest socket can accept connections on. hv_sock divides the socket port namespace into two parts for server side (listening socket), 0-0x7FFFFFFF & 0x80000000-0xFFFFFFFF (there are no restrictions on client port namespace). The first part (0-0x7FFFFFFF) is reserved for sockets where connections can be accepted. The second part (0x80000000-0xFFFFFFFF) is reserved for allocating ports for the peer (host) socket, once a connection is accepted. This reservation of the port namespace is specific to hv_sock and not known by the generic vsock library (ex: af_vsock). This is problematic because auto-binds/ephemeral ports are handled by the generic vsock library and it has no knowledge of this port reservation and could allocate a port that is not compatible with hv_sock (and legitimately so). The issue hasn't surfaced so far because the auto-bind code of vsock (__vsock_bind_stream) prior to the change 'VSOCK: bind to random port for VMADDR_PORT_ANY' would start walking up from LAST_RESERVED_PORT (1023) and start assigning ports. That will take a large number of iterations to hit 0x7FFFFFFF. But, after the above change to randomize port selection, the issue has started coming up more frequently.
There has really been no good reason to have this port reservation logic in hv_sock from the get go. Reserving a local port for peer ports is not how things are handled generally. Peer ports should reflect the peer port. This fixes the issue by lifting the port reservation, and also returns the right peer port. Since the code converts the GUID to the peer port (by using the first 4 bytes), there is a possibility of conflicts, but that seems like a reasonable risk to take, given this is limited to vsock and that only applies to all local sockets.
--- net/vmw_vsock/hyperv_transport.c | 68 +++++--------------------------- 1 file changed, 9 insertions(+), 59 deletions(-)
net/vmw_vsock/hyperv_transport.c +9 -59
@@ -144,28 +144,15 @@ struct hvsock {**************************************************************************** * The only valid Service GUIDs, from the perspectives of both the host and * * Linux VM, that can be connected by the other end, must conform to this * -* format: <port>-facb-11e6-bd58-64006a7986d3, and the "port" must be in * -* this range [0, 0x7FFFFFFF]. * +* format: <port>-facb-11e6-bd58-64006a7986d3. * **************************************************************************** * * When we write apps on the host to connect(), the GUID ServiceID is used. * When we write apps in Linux VM to connect(), we only need to specify the * port and the driver will form the GUID and use that to request the host. * -* From the perspective of Linux VM: -* 1. the local ephemeral port (i.e. the local auto-bound port when we call -* connect() without explicit bind()) is generated by __vsock_bind_stream(), -* and the range is [1024, 0xFFFFFFFF). -* 2. the remote ephemeral port (i.e. the auto-generated remote port for -* a connect request initiated by the host's connect()) is generated by -* hvs_remote_addr_init() and the range is [0x80000000, 0xFFFFFFFF). */ -#define MAX_LISTEN_PORT ((u32)0x7FFFFFFF) -#define MAX_VM_LISTEN_PORT MAX_LISTEN_PORT -#define MAX_HOST_LISTEN_PORT MAX_LISTEN_PORT -#define MIN_HOST_EPHEMERAL_PORT (MAX_HOST_LISTEN_PORT + 1) -/* 00000000-facb-11e6-bd58-64006a7986d3 */ static const uuid_le srv_id_template = UUID_LE(0x00000000, 0xfacb, 0x11e6, 0xbd, 0x58,
@@ -188,33 +175,6 @@ static void hvs_addr_init(struct sockaddr_vm *addr, const uuid_le *svr_id)vsock_addr_init (addr,VMADDR_CID_ANY , port); } -static void hvs_remote_addr_init (struct sockaddr_vm *remote, -struct sockaddr_vm *local) -{ -static u32 host_ephemeral_port =MIN_HOST_EPHEMERAL_PORT ; -struct sock *sk; - -vsock_addr_init (remote,VMADDR_CID_ANY ,VMADDR_PORT_ANY ); - -while (1 ) { -/* Wrap around ? */ -if (host_ephemeral_port <MIN_HOST_EPHEMERAL_PORT || - host_ephemeral_port ==VMADDR_PORT_ANY ) - host_ephemeral_port =MIN_HOST_EPHEMERAL_PORT ; - - remote->svm_port = host_ephemeral_port++; - - sk =vsock_find_connected_socket (remote, local); -if (!sk) { -/* Found an available ephemeral port */ -return ; - } - -/* Release refcnt got in vsock_find_connected_socket */ -sock_put (sk); - } -} -static void hvs_set_channel_pending_send_size (struct vmbus_channel *chan) { set_channel_pending_send_size(chan,
@@ -342,12 +302,7 @@ static void hvs_open_connection(struct vmbus_channel *chan) if_type = &chan->offermsg.offer.if_type; if_instance = &chan->offermsg.offer.if_instance; conn_from_host = chan->offermsg.offer.u.pipe.user_def[0 ]; - -/* The host or the VM should only listen on a port in -* [0, MAX_LISTEN_PORT] -*/ -if (!is_valid_srv_id (if_type) || -get_port_by_srv_id (if_type) >MAX_LISTEN_PORT ) +if (!is_valid_srv_id (if_type))return ;hvs_addr_init (&addr, conn_from_host ? if_type : if_instance);
@@ -372,6 +327,13 @@ static void hvs_open_connection(struct vmbus_channel *chan) new->sk_state =TCP_SYN_SENT ; vnew =vsock_sk (new); + +hvs_addr_init (&vnew->local_addr, if_type); + +/* Remote peer is always the host */ +vsock_addr_init (&vnew->remote_addr, +VMADDR_CID_HOST ,VMADDR_PORT_ANY ); + vnew->remote_addr.svm_port =get_port_by_srv_id (if_instance); hvs_new = vnew->trans; hvs_new->chan = chan; }else {
@@ -411,8 +373,6 @@ static void hvs_open_connection(struct vmbus_channel *chan) sk->sk_ack_backlog++;hvs_addr_init (&vnew->local_addr, if_type); -hvs_remote_addr_init (&vnew->remote_addr, &vnew->local_addr); - hvs_new->vm_srv_id = *if_type; hvs_new->host_srv_id = *if_instance;
@@ -717,16 +677,6 @@ static bool hvs_stream_is_active(struct vsock_sock *vsk)static bool hvs_stream_allow (u32 cid,u32 port) { -/* The host's port range [MIN_HOST_EPHEMERAL_PORT, 0xFFFFFFFF) is -* reserved as ephemeral ports, which are used as the host's ports -* when the host initiates connections. -* -* Perform this check in the guest so an immediate error is produced -* instead of a timeout. -*/ -if (port >MAX_HOST_LISTEN_PORT ) -return false; -if (cid ==VMADDR_CID_HOST )return true;
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 143/173 RDMA/netlink: Do not always generate an ACK for some netlink operations
In reply to Greg Kroah-HartmanFrom: Håkon Bugge <[email protected]>
commit a242c36951ecd24bc16086940dbe6b522205c461 upstream.
In rdma_nl_rcv_skb(), the local variable err is assigned the return value of the supplied callback function, which could be one of ib_nl_handle_resolve_resp(), ib_nl_handle_set_timeout(), or ib_nl_handle_ip_res_resp(). These three functions all return skb->len on success.
rdma_nl_rcv_skb() is merely a copy of netlink_rcv_skb(). The callback functions used by the latter have the convention: "Returns 0 on success or a negative error code".
In particular, the statement (equal for both functions):
if (nlh->nlmsg_flags & NLM_F_ACK || err)
implies that rdma_nl_rcv_skb() always will ack a message, independent of the NLM_F_ACK being set in nlmsg_flags or not.
The fix could be to change the above statement, but it is better to keep the two *_rcv_skb() functions equal in this respect and instead change the three callback functions in the rdma subsystem to the correct convention.
--- drivers/infiniband/core/addr.c | 2 +- drivers/infiniband/core/sa_query.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-)
drivers/infiniband/core/addr.c +1 -1
@@ -140,7 +140,7 @@ int ib_nl_handle_ip_res_resp(struct sk_bif (ib_nl_is_good_ip_resp (nlh))ib_nl_process_good_ip_rsep (nlh); -return skb->len; +return 0 ; } static int ib_nl_ip_send_msg(struct rdma_dev_addr *dev_addr,
drivers/infiniband/core/sa_query.c +2 -2
@@ -1078,7 +1078,7 @@ int ib_nl_handle_set_timeout(struct sk_b } settimeout_out: -return skb->len; +return 0 ; }static inline int ib_nl_is_good_resolve_resp (const struct nlmsghdr *nlh)
@@ -1149,7 +1149,7 @@ int ib_nl_handle_resolve_resp(struct sk_ } resp_out: -return skb->len; +return 0 ; }static void free_sm_ah (struct kref *kref)
Greg Kroah-Hartman
maintainerPATCH 128/173 KVM: x86: Protect pmu_intel.c from Spectre-v1/L1TF attacks
In reply to Greg Kroah-HartmanFrom: Marios Pomonis <[email protected]>
[ Upstream commit 66061740f1a487f4ed54fde75e724709f805da53 ]
This fixes Spectre-v1/L1TF vulnerabilities in intel_find_fixed_event() and intel_rdpmc_ecx_to_pmc().kvm_rdpmc() (ancestor of intel_find_fixed_event()) and reprogram_fixed_counter() (ancestor of intel_rdpmc_ecx_to_pmc()) are exported symbols so KVM should treat them conservatively from a security perspective.
--- arch/x86/kvm/pmu_intel.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-)
arch/x86/kvm/pmu_intel.c +16 -8
@@ -87,10 +87,14 @@ static unsigned intel_find_arch_event(struct kvm_pmu *pmu,static unsigned intel_find_fixed_event (int idx) { -if (idx >=ARRAY_SIZE (fixed_pmc_events)) +u32 event; +size_t size =ARRAY_SIZE (fixed_pmc_events); + +if (idx >= size)return PERF_COUNT_HW_MAX ; -return intel_arch_events[fixed_pmc_events[idx]].event_type; + event = fixed_pmc_events[array_index_nospec (idx, size)]; +return intel_arch_events[event].event_type; }/* check if a PMC is enabled by comparing it with globl_ctrl bits. */
@@ -131,15 +135,19 @@ static struct kvm_pmc *intel_msr_idx_to_pmc(struct kvm_vcpu *vcpu,struct kvm_pmu *pmu =vcpu_to_pmu (vcpu);bool fixed = idx & (1u <<30 );struct kvm_pmc *counters; +unsigned int num_counters; idx &= ~(3u <<30 ); -if (!fixed && idx >= pmu->nr_arch_gp_counters) -return NULL ; -if (fixed && idx >= pmu->nr_arch_fixed_counters) +if (fixed) { + counters = pmu->fixed_counters; + num_counters = pmu->nr_arch_fixed_counters; + }else { + counters = pmu->gp_counters; + num_counters = pmu->nr_arch_gp_counters; + } +if (idx >= num_counters)return NULL ; - counters = fixed ? pmu->fixed_counters : pmu->gp_counters; - -return &counters[idx]; +return &counters[array_index_nospec (idx, num_counters)]; }static bool intel_is_valid_msr (struct kvm_vcpu *vcpu,u32 msr)
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 139/173 perf/core: Fix mlock accounting in perf_mmap()
In reply to Greg Kroah-HartmanFrom: Song Liu <[email protected]>
commit 003461559ef7a9bd0239bae35a22ad8924d6e9ad upstream.
Decreasing sysctl_perf_event_mlock between two consecutive perf_mmap()s of a perf ring buffer may lead to an integer underflow in locked memory accounting. This may lead to the undesired behaviors, such as failures in BPF map creation.
Address this by adjusting the accounting logic to take into account the possibility that the amount of already locked memory may exceed the current limit.
--- kernel/events/core.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
kernel/events/core.c +9 -1
@@ -5441,7 +5441,15 @@ accounting:*/ user_lock_limit *=num_online_cpus (); - user_locked =atomic_long_read (&user->locked_vm) + user_extra; + user_locked =atomic_long_read (&user->locked_vm); + +/* +* sysctl_perf_event_mlock may have changed, so that +* user->locked_vm > user_lock_limit +*/ +if (user_locked > user_lock_limit) + user_locked = user_lock_limit; + user_locked += user_extra;if (user_locked > user_lock_limit) extra = user_locked - user_lock_limit;
Greg Kroah-Hartman
maintainerPATCH 137/173 cifs: fail i/o on soft mounts if sessionsetup errors out
In reply to Greg Kroah-HartmanFrom: Ronnie Sahlberg <[email protected]>
commit b0dd940e582b6a60296b9847a54012a4b080dc72 upstream.
RHBZ: 1579050
If we have a soft mount we should fail commands for session-setup failures (such as the password having changed/ account being deleted/ ...) and return an error back to the application.
--- fs/cifs/smb2pdu.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
fs/cifs/smb2pdu.c +8 -2
@@ -257,9 +257,14 @@ smb2_reconnect(__le16 smb2_command, stru } rc =cifs_negotiate_protocol (0 , tcon->ses); -if (!rc && tcon->ses->need_reconnect) +if (!rc && tcon->ses->need_reconnect) { rc =cifs_setup_session (0 , tcon->ses, nls_codepage); - +if ((rc == -EACCES ) && !tcon->retry) { + rc = -EHOSTDOWN ; +mutex_unlock (&tcon->ses->session_mutex); + goto failed; + } + }if (rc || !tcon->need_reconnect) {mutex_unlock (&tcon->ses->session_mutex); goto out;
@@ -301,6 +306,7 @@ out:case SMB2_SET_INFO : rc = -EAGAIN ; } +failed:unload_nls (nls_codepage);return rc; }
Greg Kroah-Hartman
maintainerPATCH 116/173 net: macb: Limit maximum GEM TX length in TSO
In reply to Greg Kroah-HartmanFrom: Harini Katakam <[email protected]>
[ Upstream commit f822e9c4ffa511a5c681cf866287d9383a3b6f1b ]
GEM_MAX_TX_LEN currently resolves to 0x3FF8 for any IP version supporting TSO with full 14bits of length field in payload descriptor. But an IP errata causes false amba_error (bit 6 of ISR) when length in payload descriptors is specified above 16387. The error occurs because the DMA falsely concludes that there is not enough space in SRAM for incoming payload. These errors were observed continuously under stress of large packets using iperf on a version where SRAM was 16K for each queue. This errata will be documented shortly and affects all versions since TSO functionality was added. Hence limit the max length to 0x3FC0 (rounded).
--- drivers/net/ethernet/cadence/macb_main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/net/ethernet/cadence/macb_main.c +5 -1
@@ -66,7 +66,11 @@/* Max length of transmit frame must be a multiple of 8 bytes */ #define MACB_TX_LEN_ALIGN 8#define MACB_MAX_TX_LEN ((unsigned int)((1 << MACB_TX_FRMLEN_SIZE) - 1) & ~((unsigned int)(MACB_TX_LEN_ALIGN - 1))) -#define GEM_MAX_TX_LEN ((unsigned int)((1 << GEM_TX_FRMLEN_SIZE) - 1) & ~((unsigned int)(MACB_TX_LEN_ALIGN - 1))) +/* Limit maximum TX length as per Cadence TSO errata. This is to avoid a +* false amba_error in TX path from the DMA assuming there is not enough +* space in the SRAM (16KB) even when there is. +*/ +#define GEM_MAX_TX_LEN (unsigned int)(0x3FC0)#define GEM_MTU_MIN_SIZE ETH_MIN_MTU#define MACB_NETIF_LSO NETIF_F_TSO
Greg Kroah-Hartman
maintainerPATCH 112/173 net: dsa: bcm_sf2: Only 7278 supports 2Gb/sec IMP port
In reply to Greg Kroah-HartmanFrom: Florian Fainelli <[email protected]>
[ Upstream commit de34d7084edd069dac5aa010cfe32bd8c4619fa6 ]
The 7445 switch clocking profiles do not allow us to run the IMP port at 2Gb/sec in a way that it is reliable and consistent. Make sure that the setting is only applied to the 7278 family.
--- drivers/net/dsa/bcm_sf2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/dsa/bcm_sf2.c +3 -1
@@ -137,7 +137,9 @@ static void bcm_sf2_imp_setup(struct dsa/* Force link status for IMP port */ reg =core_readl (priv, offset); - reg |= (MII_SW_OR |LINK_STS |GMII_SPEED_UP_2G ); + reg |= (MII_SW_OR |LINK_STS ); +if (priv->type ==BCM7278_DEVICE_ID ) + reg |=GMII_SPEED_UP_2G ;core_writel (priv, reg, offset);/* Enable Broadcast, Multicast, Unicast forwarding to IMP port */
Greg Kroah-Hartman
maintainerPATCH 126/173 drm: atmel-hlcdc: enable clock before configuring timing engine
In reply to Greg Kroah-HartmanFrom: Claudiu Beznea <[email protected]>
[ Upstream commit 2c1fb9d86f6820abbfaa38a6836157c76ccb4e7b ]
Changing pixel clock source without having this clock source enabled will block the timing engine and the next operations after (in this case setting ATMEL_HLCDC_CFG(5) settings in atmel_hlcdc_crtc_mode_set_nofb() will fail). It is recomended (although in datasheet this is not present) to actually enabled pixel clock source before doing any changes on timing enginge (only SAM9X60 datasheet specifies that the peripheral clock and pixel clock must be enabled before using LCD controller).
--- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c +7 -1
@@ -79,7 +79,11 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)struct videomode vm;unsigned long prate;unsigned int cfg; -int div; +int div, ret; + + ret =clk_prepare_enable (crtc->dc->hlcdc->sys_clk); +if (ret) +return ; vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay; vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end;
@@ -138,6 +142,8 @@ static void atmel_hlcdc_crtc_mode_set_nofb(struct drm_crtc *c)ATMEL_HLCDC_VSPSU |ATMEL_HLCDC_VSPHO |ATMEL_HLCDC_GUARDTIME_MASK |ATMEL_HLCDC_MODE_MASK , cfg); + +clk_disable_unprepare (crtc->dc->hlcdc->sys_clk); } static enum drm_mode_status
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 124/173 btrfs: remove trivial locking wrappers of tree mod log
In reply to Greg Kroah-HartmanFrom: David Sterba <[email protected]>
[ Upstream commit b1a09f1ec540408abf3a50d15dff5d9506932693 ]
The wrappers are trivial and do not bring any extra value on top of the plain locking primitives.
--- fs/btrfs/ctree.c | 58 ++++++++++++++++-------------------------------- 1 file changed, 19 insertions(+), 39 deletions(-)
fs/btrfs/ctree.c +19 -39
@@ -334,26 +334,6 @@ struct tree_mod_elem {struct tree_mod_root old_root; }; -static inline void tree_mod_log_read_lock (struct btrfs_fs_info *fs_info) -{ -read_lock (&fs_info->tree_mod_log_lock); -} - -static inline void tree_mod_log_read_unlock (struct btrfs_fs_info *fs_info) -{ -read_unlock (&fs_info->tree_mod_log_lock); -} - -static inline void tree_mod_log_write_lock (struct btrfs_fs_info *fs_info) -{ -write_lock (&fs_info->tree_mod_log_lock); -} - -static inline void tree_mod_log_write_unlock (struct btrfs_fs_info *fs_info) -{ -write_unlock (&fs_info->tree_mod_log_lock); -} -/* * Pull a new tree mod seq number for our operation. */
@@ -373,14 +353,14 @@ static inline u64 btrfs_inc_tree_mod_seq(struct btrfs_fs_info *fs_info)u64 btrfs_get_tree_mod_seq (struct btrfs_fs_info *fs_info,struct seq_list *elem) { -tree_mod_log_write_lock (fs_info); +write_lock (&fs_info->tree_mod_log_lock);spin_lock (&fs_info->tree_mod_seq_lock);if (!elem->seq) { elem->seq =btrfs_inc_tree_mod_seq (fs_info);list_add_tail (&elem->list, &fs_info->tree_mod_seq_list); }spin_unlock (&fs_info->tree_mod_seq_lock); -tree_mod_log_write_unlock (fs_info); +write_unlock (&fs_info->tree_mod_log_lock);return elem->seq; }
@@ -422,7 +402,7 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info,* anything that's lower than the lowest existing (read: blocked) * sequence number can be removed from the tree. */ -tree_mod_log_write_lock (fs_info); +write_lock (&fs_info->tree_mod_log_lock); tm_root = &fs_info->tree_mod_log;for (node =rb_first (tm_root); node; node = next) { next =rb_next (node);
@@ -432,7 +412,7 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info,rb_erase (node, tm_root);kfree (tm); } -tree_mod_log_write_unlock (fs_info); +write_unlock (&fs_info->tree_mod_log_lock); }/*
@@ -443,7 +423,7 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info,* for root replace operations, or the logical address of the affected * block for all other operations. * -* Note: must be called with write lock (tree_mod_log_write_lock). +* Note: must be called with write lock for fs_info::tree_mod_log_lock. */ static noinline int__tree_mod_log_insert (struct btrfs_fs_info *fs_info,struct tree_mod_elem *tm)
@@ -481,7 +461,7 @@ __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)* Determines if logging can be omitted. Returns 1 if it can. Otherwise, it * returns zero with the tree_mod_log_lock acquired. The caller must hold * this until all tree mod log insertions are recorded in the rb tree and then -* call tree_mod_log_write_unlock() to release. +* write unlock fs_info::tree_mod_log_lock. */ static inline int tree_mod_dont_log (struct btrfs_fs_info *fs_info,struct extent_buffer *eb) {
@@ -491,9 +471,9 @@ static inline int tree_mod_dont_log(struct btrfs_fs_info *fs_info,if (eb &&btrfs_header_level (eb) ==0 )return 1 ; -tree_mod_log_write_lock (fs_info); +write_lock (&fs_info->tree_mod_log_lock);if (list_empty (&(fs_info)->tree_mod_seq_list)) { -tree_mod_log_write_unlock (fs_info); +write_unlock (&fs_info->tree_mod_log_lock);return 1 ; }
@@ -557,7 +537,7 @@ tree_mod_log_insert_key(struct btrfs_fs_info *fs_info, } ret =__tree_mod_log_insert (fs_info, tm); -tree_mod_log_write_unlock (fs_info); +write_unlock (&eb->fs_info->tree_mod_log_lock);if (ret)kfree (tm);
@@ -621,7 +601,7 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info, ret =__tree_mod_log_insert (fs_info, tm);if (ret) goto free_tms; -tree_mod_log_write_unlock (fs_info); +write_unlock (&eb->fs_info->tree_mod_log_lock);kfree (tm_list);return 0 ;
@@ -632,7 +612,7 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,kfree (tm_list[i]); }if (locked) -tree_mod_log_write_unlock (fs_info); +write_unlock (&eb->fs_info->tree_mod_log_lock);kfree (tm_list);kfree (tm);
@@ -713,7 +693,7 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,if (!ret) ret =__tree_mod_log_insert (fs_info, tm); -tree_mod_log_write_unlock (fs_info); +write_unlock (&fs_info->tree_mod_log_lock);if (ret) goto free_tms;kfree (tm_list);
@@ -740,7 +720,7 @@ __tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq,struct tree_mod_elem *cur =NULL ;struct tree_mod_elem *found =NULL ; -tree_mod_log_read_lock (fs_info); +read_lock (&fs_info->tree_mod_log_lock); tm_root = &fs_info->tree_mod_log; node = tm_root->rb_node;while (node) {
@@ -768,7 +748,7 @@ __tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq,break ; } } -tree_mod_log_read_unlock (fs_info); +read_unlock (&fs_info->tree_mod_log_lock);return found; }
@@ -849,7 +829,7 @@ tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst, goto free_tms; } -tree_mod_log_write_unlock (fs_info); +write_unlock (&fs_info->tree_mod_log_lock);kfree (tm_list);return 0 ;
@@ -861,7 +841,7 @@ tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,kfree (tm_list[i]); }if (locked) -tree_mod_log_write_unlock (fs_info); +write_unlock (&fs_info->tree_mod_log_lock);kfree (tm_list);return ret;
@@ -921,7 +901,7 @@ tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb) goto free_tms; ret =__tree_mod_log_free_eb (fs_info, tm_list, nritems); -tree_mod_log_write_unlock (fs_info); +write_unlock (&eb->fs_info->tree_mod_log_lock);if (ret) goto free_tms;kfree (tm_list);
@@ -1279,7 +1259,7 @@ __tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,unsigned long p_size =sizeof (struct btrfs_key_ptr ); n =btrfs_header_nritems (eb); -tree_mod_log_read_lock (fs_info); +read_lock (&fs_info->tree_mod_log_lock);while (tm && tm->seq >= time_seq) {/* * all the operations are recorded with the operator used for
@@ -1334,7 +1314,7 @@ __tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb,if (tm->logical != first_tm->logical)break ; } -tree_mod_log_read_unlock (fs_info); +read_unlock (&fs_info->tree_mod_log_lock);btrfs_set_header_nritems (eb, n); }
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 120/173 Btrfs: fix assertion failure on fsync with NO_HOLES enabled
In reply to Greg Kroah-HartmanFrom: Filipe Manana <[email protected]>
[ Upstream commit 0ccc3876e4b2a1559a4dbe3126dda4459d38a83b ]
Back in commit a89ca6f24ffe4 ("Btrfs: fix fsync after truncate when no_holes feature is enabled") I added an assertion that is triggered when an inline extent is found to assert that the length of the (uncompressed) data the extent represents is the same as the i_size of the inode, since that is true most of the time I couldn't find or didn't remembered about any exception at that time. Later on the assertion was expanded twice to deal with a case of a compressed inline extent representing a range that matches the sector size followed by an expanding truncate, and another case where fallocate can update the i_size of the inode without adding or updating existing extents (if the fallocate range falls entirely within the first block of the file). These two expansion/fixes of the assertion were done by commit 7ed586d0a8241 ("Btrfs: fix assertion on fsync of regular file when using no-holes feature") and commit 6399fb5a0b69a ("Btrfs: fix assertion failure during fsync in no-holes mode"). These however missed the case where an falloc expands the i_size of an inode to exactly the sector size and inline extent exists, for example:
$ mkfs.btrfs -f -O no-holes /dev/sdc $ mount /dev/sdc /mnt
$ xfs_io -f -c "pwrite -S 0xab 0 1096" /mnt/foobar wrote 1096/1096 bytes at offset 0 1 KiB, 1 ops; 0.0002 sec (4.448 MiB/sec and 4255.3191 ops/sec)
$ xfs_io -c "falloc 1096 3000" /mnt/foobar $ xfs_io -c "fsync" /mnt/foobar Segmentation fault
$ dmesg [701253.602385] assertion failed: len == i_size || (len == fs_info->sectorsize && btrfs_file_extent_compression(leaf, extent) != BTRFS_COMPRESS_NONE) || (len < i_size && i_size < fs_info->sectorsize), file: fs/btrfs/tree-log.c, line: 4727 [701253.602962] ------------[ cut here ]------------ [701253.603224] kernel BUG at fs/btrfs/ctree.h:3533! [701253.603503] invalid opcode: 0000 [#1] SMP DEBUG_PAGEALLOC PTI [701253.603774] CPU: 2 PID: 7192 Comm: xfs_io Tainted: G W 5.0.0-rc8-btrfs-next-45 #1 [701253.604054] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.11.2-0-gf9626ccb91-prebuilt.qemu-project.org 04/01/2014 [701253.604650] RIP: 0010:assfail.constprop.23+0x18/0x1a [btrfs] (...) [701253.605591] RSP: 0018:ffffbb48c186bc48 EFLAGS: 00010286 [701253.605914] RAX: 00000000000000de RBX: ffff921d0a7afc08 RCX: 0000000000000000 [701253.606244] RDX: 0000000000000000 RSI: ffff921d36b16868 RDI: ffff921d36b16868 [701253.606580] RBP: ffffbb48c186bcf0 R08: 0000000000000000 R09: 0000000000000000 [701253.606913] R10: 0000000000000003 R11: 0000000000000000 R12: ffff921d05d2de18 [701253.607247] R13: ffff921d03b54000 R14: 0000000000000448 R15: ffff921d059ecf80 [701253.607769] FS: 00007f14da906700(0000) GS:ffff921d36b00000(0000) knlGS:0000000000000000 [701253.608163] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [701253.608516] CR2: 000056087ea9f278 CR3: 00000002268e8001 CR4: 00000000003606e0 [701253.608880] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [701253.609250] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [701253.609608] Call Trace: [701253.609994] btrfs_log_inode+0xdfb/0xe40 [btrfs] [701253.610383] btrfs_log_inode_parent+0x2be/0xa60 [btrfs] [701253.610770] ? do_raw_spin_unlock+0x49/0xc0 [701253.611150] btrfs_log_dentry_safe+0x4a/0x70 [btrfs] [701253.611537] btrfs_sync_file+0x3b2/0x440 [btrfs] [701253.612010] ? do_sysinfo+0xb0/0xf0 [701253.612552] do_fsync+0x38/0x60 [701253.612988] __x64_sys_fsync+0x10/0x20 [701253.613360] do_syscall_64+0x60/0x1b0 [701253.613733] entry_SYSCALL_64_after_hwframe+0x49/0xbe [701253.614103] RIP: 0033:0x7f14da4e66d0 (...) [701253.615250] RSP: 002b:00007fffa670fdb8 EFLAGS: 00000246 ORIG_RAX: 000000000000004a [701253.615647] RAX: ffffffffffffffda RBX: 0000000000000001 RCX: 00007f14da4e66d0 [701253.616047] RDX: 000056087ea9c260 RSI: 000056087ea9c260 RDI: 0000000000000003 [701253.616450] RBP: 0000000000000001 R08: 0000000000000020 R09: 0000000000000010 [701253.616854] R10: 000000000000009b R11: 0000000000000246 R12: 000056087ea9c260 [701253.617257] R13: 000056087ea9c240 R14: 0000000000000000 R15: 000056087ea9dd10 (...) [701253.619941] ---[ end trace e088d74f132b6da5 ]---
Updating the assertion again to allow for this particular case would result in a meaningless assertion, plus there is currently no risk of logging content that would result in any corruption after a log replay if the size of the data encoded in an inline extent is greater than the inode's i_size (which is not currently possibe either with or without compression), therefore just remove the assertion.
--- fs/btrfs/tree-log.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-)
fs/btrfs/tree-log.c +1 -8
@@ -4727,15 +4727,8 @@ static int btrfs_log_trailing_hole(struct btrfs_trans_handle *trans, struct btrfs_file_extent_item);if (btrfs_file_extent_type (leaf, extent) == -BTRFS_FILE_EXTENT_INLINE ) { - len =btrfs_file_extent_ram_bytes (leaf, extent); -ASSERT (len == i_size || - (len == fs_info->sectorsize && -btrfs_file_extent_compression (leaf, extent) != -BTRFS_COMPRESS_NONE ) || - (len < i_size && i_size < fs_info->sectorsize)); +BTRFS_FILE_EXTENT_INLINE )return 0 ; - } len =btrfs_file_extent_num_bytes (leaf, extent);/* Last extent goes beyond i_size, no need to log a hole. */
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 121/173 Btrfs: fix missing hole after hole punching and fsync when using NO_HOLES
In reply to Greg Kroah-HartmanFrom: Filipe Manana <[email protected]>
[ Upstream commit 0e56315ca147b3e60c7bf240233a301d3c7fb508 ]
When using the NO_HOLES feature, if we punch a hole into a file and then fsync it, there are cases where a subsequent fsync will miss the fact that a hole was punched, resulting in the holes not existing after replaying the log tree.
Essentially these cases all imply that, tree-log.c:copy_items(), is not invoked for the leafs that delimit holes, because nothing changed those leafs in the current transaction. And it's precisely copy_items() where we currenly detect and log holes, which works as long as the holes are between file extent items in the input leaf or between the beginning of input leaf and the previous leaf or between the last item in the leaf and the next leaf.
First example where we miss a hole:
*) The extent items of the inode span multiple leafs;
*) The punched hole covers a range that affects only the extent items of
the first leaf;
*) The fsync operation is done in full mode (BTRFS_INODE_NEEDS_FULL_SYNC
is set in the inode's runtime flags).
That results in the hole not existing after replaying the log tree.
For example, if the fs/subvolume tree has the following layout for a particular inode:
Leaf N, generation 10:
[ ... INODE_ITEM INODE_REF EXTENT_ITEM (0 64K) EXTENT_ITEM (64K 128K) ]
Leaf N + 1, generation 10:
[ EXTENT_ITEM (128K 64K) ... ]
If at transaction 11 we punch a hole coverting the range [0, 128K[, we end up dropping the two extent items from leaf N, but we don't touch the other leaf, so we end up in the following state:
Leaf N, generation 11:
[ ... INODE_ITEM INODE_REF ]
Leaf N + 1, generation 10:
[ EXTENT_ITEM (128K 64K) ... ]
A full fsync after punching the hole will only process leaf N because it was modified in the current transaction, but not leaf N + 1, since it was not modified in the current transaction (generation 10 and not 11). As a result the fsync will not log any holes, because it didn't process any leaf with extent items.
Second example where we will miss a hole:
*) An inode as its items spanning 5 (or more) leafs;
*) A hole is punched and it covers only the extents items of the 3rd
leaf. This resulsts in deleting the entire leaf and not touching any of the other leafs.
So the only leaf that is modified in the current transaction, when punching the hole, is the first leaf, which contains the inode item. During the full fsync, the only leaf that is passed to copy_items() is that first leaf, and that's not enough for the hole detection code in copy_items() to determine there's a hole between the last file extent item in the 2nd leaf and the first file extent item in the 3rd leaf (which was the 4th leaf before punching the hole).
Fix this by scanning all leafs and punch holes as necessary when doing a full fsync (less common than a non-full fsync) when the NO_HOLES feature is enabled. The lack of explicit file extent items to mark holes makes it necessary to scan existing extents to determine if holes exist.
A test case for fstests follows soon.
--- fs/btrfs/tree-log.c | 388 ++++++++++++-------------------------------- 1 file changed, 100 insertions(+), 288 deletions(-)
fs/btrfs/tree-log.c +100 -288
@@ -3758,7 +3758,7 @@ static int log_inode_item(struct btrfs_trans_handle *trans, static noinline int copy_items(struct btrfs_trans_handle *trans,struct btrfs_inode *inode,struct btrfs_path *dst_path, -struct btrfs_path *src_path,u64 *last_extent, +struct btrfs_path *src_path,int start_slot,int nr,int inode_only,u64 logged_isize) {
@@ -3769,7 +3769,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,struct btrfs_file_extent_item *extent;struct btrfs_inode_item *inode_item;struct extent_buffer *src = src_path->nodes[0 ]; -struct btrfs_key first_key, last_key, key;int ret;struct btrfs_key *ins_keys;u32 *ins_sizes;
@@ -3777,9 +3776,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,int i;struct list_head ordered_sums;int skip_csum = inode->flags &BTRFS_INODE_NODATASUM ; -bool has_extents = false; -bool need_find_last_extent = true; -bool done = false;INIT_LIST_HEAD (&ordered_sums);
@@ -3788,8 +3784,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,if (!ins_data)return -ENOMEM ; - first_key.objectid = (u64)-1 ; - ins_sizes = (u32 *)ins_data; ins_keys = (struct btrfs_key *)(ins_data + nr *sizeof (u32));
@@ -3810,9 +3804,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, src_offset =btrfs_item_ptr_offset (src, start_slot + i); -if (i == nr -1 ) - last_key = ins_keys[i]; -if (ins_keys[i].type ==BTRFS_INODE_ITEM_KEY ) { inode_item = btrfs_item_ptr(dst_path->nodes[0], dst_path->slots[0],
@@ -3826,20 +3817,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, src_offset, ins_sizes[i]); } -/* -* We set need_find_last_extent here in case we know we were -* processing other items and then walk into the first extent in -* the inode. If we don't hit an extent then nothing changes, -* we'll do the last search the next time around. -*/ -if (ins_keys[i].type ==BTRFS_EXTENT_DATA_KEY ) { - has_extents = true; -if (first_key.objectid == (u64)-1 ) - first_key = ins_keys[i]; - }else { - need_find_last_extent = false; - } -/* take a reference on file data extents so that truncates * or deletes of this inode don't have to relog the inode * again
@@ -3905,167 +3882,6 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,kfree (sums); } -if (!has_extents) -return ret; - -if (need_find_last_extent && *last_extent == first_key.offset) { -/* -* We don't have any leafs between our current one and the one -* we processed before that can have file extent items for our -* inode (and have a generation number smaller than our current -* transaction id). -*/ - need_find_last_extent = false; - } - -/* -* Because we use btrfs_search_forward we could skip leaves that were -* not modified and then assume *last_extent is valid when it really -* isn't. So back up to the previous leaf and read the end of the last -* extent before we go and fill in holes. -*/ -if (need_find_last_extent) { -u64 len; - - ret =btrfs_prev_leaf (inode->root, src_path); -if (ret <0 ) -return ret; -if (ret) - goto fill_holes; -if (src_path->slots[0 ]) - src_path->slots[0 ]--; - src = src_path->nodes[0 ]; -btrfs_item_key_to_cpu (src, &key, src_path->slots[0 ]); -if (key.objectid !=btrfs_ino (inode) || - key.type !=BTRFS_EXTENT_DATA_KEY ) - goto fill_holes; - extent =btrfs_item_ptr (src, src_path->slots[0 ], - struct btrfs_file_extent_item); -if (btrfs_file_extent_type (src, extent) == -BTRFS_FILE_EXTENT_INLINE ) { - len =btrfs_file_extent_ram_bytes (src, extent); - *last_extent =ALIGN (key.offset + len, - fs_info->sectorsize); - }else { - len =btrfs_file_extent_num_bytes (src, extent); - *last_extent = key.offset + len; - } - } -fill_holes: -/* So we did prev_leaf, now we need to move to the next leaf, but a few -* things could have happened -* -* 1) A merge could have happened, so we could currently be on a leaf -* that holds what we were copying in the first place. -* 2) A split could have happened, and now not all of the items we want -* are on the same leaf. -* -* So we need to adjust how we search for holes, we need to drop the -* path and re-search for the first extent key we found, and then walk -* forward until we hit the last one we copied. -*/ -if (need_find_last_extent) { -/* btrfs_prev_leaf could return 1 without releasing the path */ -btrfs_release_path (src_path); - ret =btrfs_search_slot (NULL , inode->root, &first_key, - src_path,0 ,0 ); -if (ret <0 ) -return ret; -ASSERT (ret ==0 ); - src = src_path->nodes[0 ]; - i = src_path->slots[0 ]; - }else { - i = start_slot; - } - -/* -* Ok so here we need to go through and fill in any holes we may have -* to make sure that holes are punched for those areas in case they had -* extents previously. -*/ -while (!done) { -u64 offset, len; -u64 extent_end; - -if (i >=btrfs_header_nritems (src_path->nodes[0 ])) { - ret =btrfs_next_leaf (inode->root, src_path); -if (ret <0 ) -return ret; -ASSERT (ret ==0 ); - src = src_path->nodes[0 ]; - i =0 ; - need_find_last_extent = true; - } - -btrfs_item_key_to_cpu (src, &key, i); -if (!btrfs_comp_cpu_keys (&key, &last_key)) - done = true; -if (key.objectid !=btrfs_ino (inode) || - key.type !=BTRFS_EXTENT_DATA_KEY ) { - i++; -continue ; - } - extent = btrfs_item_ptr(src, i, struct btrfs_file_extent_item); -if (btrfs_file_extent_type (src, extent) == -BTRFS_FILE_EXTENT_INLINE ) { - len =btrfs_file_extent_ram_bytes (src, extent); - extent_end =ALIGN (key.offset + len, - fs_info->sectorsize); - }else { - len =btrfs_file_extent_num_bytes (src, extent); - extent_end = key.offset + len; - } - i++; - -if (*last_extent == key.offset) { - *last_extent = extent_end; -continue ; - } - offset = *last_extent; - len = key.offset - *last_extent; - ret =btrfs_insert_file_extent (trans, log,btrfs_ino (inode), - offset,0 ,0 , len,0 , len,0 ,0 ,0 ); -if (ret) -break ; - *last_extent = extent_end; - } - -/* -* Check if there is a hole between the last extent found in our leaf -* and the first extent in the next leaf. If there is one, we need to -* log an explicit hole so that at replay time we can punch the hole. -*/ -if (ret ==0 && - key.objectid ==btrfs_ino (inode) && - key.type ==BTRFS_EXTENT_DATA_KEY && - i ==btrfs_header_nritems (src_path->nodes[0 ])) { - ret =btrfs_next_leaf (inode->root, src_path); - need_find_last_extent = true; -if (ret >0 ) { - ret =0 ; - }else if (ret ==0 ) { -btrfs_item_key_to_cpu (src_path->nodes[0 ], &key, - src_path->slots[0 ]); -if (key.objectid ==btrfs_ino (inode) && - key.type ==BTRFS_EXTENT_DATA_KEY && - *last_extent < key.offset) { -const u64 len = key.offset - *last_extent; - - ret =btrfs_insert_file_extent (trans, log, -btrfs_ino (inode), - *last_extent,0 , -0 , len,0 , len, -0 ,0 ,0 ); - *last_extent += len; - } - } - } -/* -* Need to let the callers know we dropped the path so they should -* re-search. -*/ -if (!ret && need_find_last_extent) - ret =1 ;return ret; }
@@ -4338,7 +4154,7 @@ static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans,const u64 i_size =i_size_read (&inode->vfs_inode);const u64 ino =btrfs_ino (inode);struct btrfs_path *dst_path =NULL ; -u64 last_extent = (u64)-1 ; +bool dropped_extents = false;int ins_nr =0 ;int start_slot;int ret;
@@ -4360,8 +4176,7 @@ static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans,if (slot >=btrfs_header_nritems (leaf)) {if (ins_nr >0 ) { ret =copy_items (trans, inode, dst_path, path, - &last_extent, start_slot, - ins_nr,1 ,0 ); + start_slot, ins_nr,1 ,0 );if (ret <0 ) goto out; ins_nr =0 ;
@@ -4385,8 +4200,7 @@ static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans, path->slots[0 ]++;continue ; } -if (last_extent == (u64)-1 ) { - last_extent = key.offset; +if (!dropped_extents) {/* * Avoid logging extent items logged in past fsync calls * and leading to duplicate keys in the log tree.
@@ -4400,6 +4214,7 @@ static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans, }while (ret == -EAGAIN );if (ret) goto out; + dropped_extents = true; }if (ins_nr ==0 ) start_slot = slot;
@@ -4414,7 +4229,7 @@ static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans, } }if (ins_nr >0 ) { - ret =copy_items (trans, inode, dst_path, path, &last_extent, + ret =copy_items (trans, inode, dst_path, path, start_slot, ins_nr,1 ,0 );if (ret >0 ) ret =0 ;
@@ -4608,13 +4423,8 @@ static int btrfs_log_all_xattrs(struct btrfs_trans_handle *trans,if (slot >= nritems) {if (ins_nr >0 ) { -u64 last_extent =0 ; - ret =copy_items (trans, inode, dst_path, path, - &last_extent, start_slot, - ins_nr,1 ,0 ); -/* can't be 1, extent items aren't processed */ -ASSERT (ret <=0 ); + start_slot, ins_nr,1 ,0 );if (ret <0 )return ret; ins_nr =0 ;
@@ -4638,13 +4448,8 @@ static int btrfs_log_all_xattrs(struct btrfs_trans_handle *trans,cond_resched (); }if (ins_nr >0 ) { -u64 last_extent =0 ; - ret =copy_items (trans, inode, dst_path, path, - &last_extent, start_slot, - ins_nr,1 ,0 ); -/* can't be 1, extent items aren't processed */ -ASSERT (ret <=0 ); + start_slot, ins_nr,1 ,0 );if (ret <0 )return ret; }
@@ -4653,100 +4458,119 @@ static int btrfs_log_all_xattrs(struct btrfs_trans_handle *trans, }/* -* If the no holes feature is enabled we need to make sure any hole between the -* last extent and the i_size of our inode is explicitly marked in the log. This -* is to make sure that doing something like: -* -* 1) create file with 128Kb of data -* 2) truncate file to 64Kb -* 3) truncate file to 256Kb -* 4) fsync file -* 5) <crash/power failure> -* 6) mount fs and trigger log replay -* -* Will give us a file with a size of 256Kb, the first 64Kb of data match what -* the file had in its first 64Kb of data at step 1 and the last 192Kb of the -* file correspond to a hole. The presence of explicit holes in a log tree is -* what guarantees that log replay will remove/adjust file extent items in the -* fs/subvol tree. -* -* Here we do not need to care about holes between extents, that is already done -* by copy_items(). We also only need to do this in the full sync path, where we -* lookup for extents from the fs/subvol tree only. In the fast path case, we -* lookup the list of modified extent maps and if any represents a hole, we -* insert a corresponding extent representing a hole in the log tree. +* When using the NO_HOLES feature if we punched a hole that causes the +* deletion of entire leafs or all the extent items of the first leaf (the one +* that contains the inode item and references) we may end up not processing +* any extents, because there are no leafs with a generation matching the +* current transaction that have extent items for our inode. So we need to find +* if any holes exist and then log them. We also need to log holes after any +* truncate operation that changes the inode's size. */ -static int btrfs_log_trailing_hole (struct btrfs_trans_handle *trans, -struct btrfs_root *root, -struct btrfs_inode *inode, -struct btrfs_path *path) +static int btrfs_log_holes (struct btrfs_trans_handle *trans, +struct btrfs_root *root, +struct btrfs_inode *inode, +struct btrfs_path *path) {struct btrfs_fs_info *fs_info = root->fs_info; -int ret;struct btrfs_key key; -u64 hole_start; -u64 hole_size; -struct extent_buffer *leaf; -struct btrfs_root *log = root->log_root;const u64 ino =btrfs_ino (inode);const u64 i_size =i_size_read (&inode->vfs_inode); +u64 prev_extent_end =0 ; +int ret; -if (!btrfs_fs_incompat (fs_info,NO_HOLES )) +if (!btrfs_fs_incompat (fs_info,NO_HOLES ) || i_size ==0 )return 0 ; key.objectid = ino; key.type =BTRFS_EXTENT_DATA_KEY ; - key.offset = (u64)-1 ; + key.offset =0 ; ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); -ASSERT (ret !=0 );if (ret <0 )return ret; -ASSERT (path->slots[0 ] >0 ); - path->slots[0 ]--; - leaf = path->nodes[0 ]; -btrfs_item_key_to_cpu (leaf, &key, path->slots[0 ]); - -if (key.objectid != ino || key.type !=BTRFS_EXTENT_DATA_KEY ) { -/* inode does not have any extents */ - hole_start =0 ; - hole_size = i_size; - }else { +while (true) {struct btrfs_file_extent_item *extent; +struct extent_buffer *leaf = path->nodes[0 ];u64 len; -/* -* If there's an extent beyond i_size, an explicit hole was -* already inserted by copy_items(). -*/ -if (key.offset >= i_size) -return 0 ; +if (path->slots[0 ] >=btrfs_header_nritems (path->nodes[0 ])) { + ret =btrfs_next_leaf (root, path); +if (ret <0 ) +return ret; +if (ret >0 ) { + ret =0 ; +break ; + } + leaf = path->nodes[0 ]; + } + +btrfs_item_key_to_cpu (leaf, &key, path->slots[0 ]); +if (key.objectid != ino || key.type !=BTRFS_EXTENT_DATA_KEY ) +break ; + +/* We have a hole, log it. */ +if (prev_extent_end < key.offset) { +const u64 hole_len = key.offset - prev_extent_end; + +/* +* Release the path to avoid deadlocks with other code +* paths that search the root while holding locks on +* leafs from the log root. +*/ +btrfs_release_path (path); + ret =btrfs_insert_file_extent (trans, root->log_root, + ino, prev_extent_end,0 , +0 , hole_len,0 , hole_len, +0 ,0 ,0 ); +if (ret <0 ) +return ret; + +/* +* Search for the same key again in the root. Since it's +* an extent item and we are holding the inode lock, the +* key must still exist. If it doesn't just emit warning +* and return an error to fall back to a transaction +* commit. +*/ + ret =btrfs_search_slot (NULL , root, &key, path,0 ,0 ); +if (ret <0 ) +return ret; +if (WARN_ON (ret >0 )) +return -ENOENT ; + leaf = path->nodes[0 ]; + } extent =btrfs_item_ptr (leaf, path->slots[0 ], struct btrfs_file_extent_item); -if (btrfs_file_extent_type (leaf, extent) == -BTRFS_FILE_EXTENT_INLINE ) -return 0 ; +BTRFS_FILE_EXTENT_INLINE ) { + len =btrfs_file_extent_ram_bytes (leaf, extent); + prev_extent_end =ALIGN (key.offset + len, + fs_info->sectorsize); + }else { + len =btrfs_file_extent_num_bytes (leaf, extent); + prev_extent_end = key.offset + len; + } - len =btrfs_file_extent_num_bytes (leaf, extent); -/* Last extent goes beyond i_size, no need to log a hole. */ -if (key.offset + len > i_size) -return 0 ; - hole_start = key.offset + len; - hole_size = i_size - hole_start; + path->slots[0 ]++; +cond_resched (); } -btrfs_release_path (path); -/* Last extent ends at i_size. */ -if (hole_size ==0 ) -return 0 ; +if (prev_extent_end < i_size) { +u64 hole_len; - hole_size =ALIGN (hole_size, fs_info->sectorsize); - ret =btrfs_insert_file_extent (trans, log, ino, hole_start,0 ,0 , - hole_size,0 , hole_size,0 ,0 ,0 ); -return ret; +btrfs_release_path (path); + hole_len =ALIGN (i_size - prev_extent_end, fs_info->sectorsize); + ret =btrfs_insert_file_extent (trans, root->log_root, + ino, prev_extent_end,0 ,0 , + hole_len,0 , hole_len, +0 ,0 ,0 ); +if (ret <0 ) +return ret; + } + +return 0 ; }/*
@@ -4914,7 +4738,6 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,struct btrfs_root *log = root->log_root;struct extent_buffer *src =NULL ;LIST_HEAD (logged_list); -u64 last_extent =0 ;int err =0 ;int ret;int nritems;
@@ -5088,7 +4911,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, ins_start_slot = path->slots[0 ]; } ret =copy_items (trans, inode, dst_path, path, - &last_extent, ins_start_slot, + ins_start_slot, ins_nr, inode_only, logged_isize);if (ret <0 ) {
@@ -5142,17 +4965,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,if (ins_nr ==0 ) goto next_slot; ret =copy_items (trans, inode, dst_path, path, - &last_extent, ins_start_slot, + ins_start_slot, ins_nr, inode_only, logged_isize);if (ret <0 ) { err = ret; goto out_unlock; } ins_nr =0 ; -if (ret) { -btrfs_release_path (path); -continue ; - } goto next_slot; }
@@ -5166,18 +4985,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, goto next_slot; } - ret =copy_items (trans, inode, dst_path, path, &last_extent, + ret =copy_items (trans, inode, dst_path, path, ins_start_slot, ins_nr, inode_only, logged_isize);if (ret <0 ) { err = ret; goto out_unlock; } -if (ret) { - ins_nr =0 ; -btrfs_release_path (path); -continue ; - } ins_nr =1 ; ins_start_slot = path->slots[0 ]; next_slot:
@@ -5191,13 +5005,12 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, }if (ins_nr) { ret =copy_items (trans, inode, dst_path, path, - &last_extent, ins_start_slot, + ins_start_slot, ins_nr, inode_only, logged_isize);if (ret <0 ) { err = ret; goto out_unlock; } - ret =0 ; ins_nr =0 ; }btrfs_release_path (path);
@@ -5212,14 +5025,13 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans, } }if (ins_nr) { - ret =copy_items (trans, inode, dst_path, path, &last_extent, + ret =copy_items (trans, inode, dst_path, path, ins_start_slot, ins_nr, inode_only, logged_isize);if (ret <0 ) { err = ret; goto out_unlock; } - ret =0 ; ins_nr =0 ; }
@@ -5232,7 +5044,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,if (max_key.type >=BTRFS_EXTENT_DATA_KEY && !fast_search) {btrfs_release_path (path);btrfs_release_path (dst_path); - err =btrfs_log_trailing_hole (trans, root, inode, path); + err =btrfs_log_holes (trans, root, inode, path);if (err) goto out_unlock; }
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 122/173 btrfs: use bool argument in free_root_pointers()
In reply to Greg Kroah-HartmanFrom: Anand Jain <[email protected]>
[ Upstream commit 4273eaff9b8d5e141113a5bdf9628c02acf3afe5 ]
We don't need int argument bool shall do in free_root_pointers(). And rename the argument as it confused two people.
--- fs/btrfs/disk-io.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
fs/btrfs/disk-io.c +5 -5
@@ -2051,7 +2051,7 @@ static void free_root_extent_buffers(struct btrfs_root *root) }/* helper to cleanup tree roots */ -static void free_root_pointers (struct btrfs_fs_info *info,int chunk_root) +static void free_root_pointers (struct btrfs_fs_info *info,bool free_chunk_root) {free_root_extent_buffers (info->tree_root);
@@ -2060,7 +2060,7 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root)free_root_extent_buffers (info->csum_root);free_root_extent_buffers (info->quota_root);free_root_extent_buffers (info->uuid_root); -if (chunk_root) +if (free_chunk_root)free_root_extent_buffers (info->chunk_root);free_root_extent_buffers (info->free_space_root); }
@@ -3069,7 +3069,7 @@ int open_ctree(struct super_block *sb,btrfs_put_block_group_cache (fs_info); fail_tree_roots: -free_root_pointers (fs_info,1 ); +free_root_pointers (fs_info, true);invalidate_inode_pages2 (fs_info->btree_inode->i_mapping); fail_sb_buffer:
@@ -3097,7 +3097,7 @@ int open_ctree(struct super_block *sb,if (!btrfs_test_opt (fs_info,USEBACKUPROOT )) goto fail_tree_roots; -free_root_pointers (fs_info,0 ); +free_root_pointers (fs_info, false);/* don't use the log in recovery mode, it won't be valid */ btrfs_set_super_log_root (disk_super,0 );
@@ -3764,7 +3764,7 @@ void close_ctree(struct btrfs_fs_info *fs_info)btrfs_free_block_groups (fs_info);clear_bit (BTRFS_FS_OPEN , &fs_info->flags); -free_root_pointers (fs_info,1 ); +free_root_pointers (fs_info, true);iput (fs_info->btree_inode);
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 117/173 bonding/alb: properly access headers in bond_alb_xmit()
In reply to Greg Kroah-HartmanFrom: Eric Dumazet <[email protected]>
[ Upstream commit 38f88c45404293bbc027b956def6c10cbd45c616 ]
syzbot managed to send an IPX packet through bond_alb_xmit() and af_packet and triggered a use-after-free.
First, bond_alb_xmit() was using ipx_hdr() helper to reach the IPX header, but ipx_hdr() was using the transport offset instead of the network offset. In the particular syzbot report transport offset was 0xFFFF
This patch removes ipx_hdr() since it was only (mis)used from bonding.
Then we need to make sure IPv4/IPv6/IPX headers are pulled in skb->head before dereferencing anything.
BUG: KASAN: use-after-free in bond_alb_xmit+0x153a/0x1590 drivers/net/bonding/bond_alb.c:1452 Read of size 2 at addr ffff8801ce56dfff by task syz-executor.2/18108 (if (ipx_hdr(skb)->ipx_checksum != IPX_NO_CHECKSUM) ...) Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: [<ffffffff8441fc42>] __dump_stack lib/dump_stack.c:17 [inline] [<ffffffff8441fc42>] dump_stack+0x14d/0x20b lib/dump_stack.c:53 [<ffffffff81a7dec4>] print_address_description+0x6f/0x20b mm/kasan/report.c:282 [<ffffffff81a7e0ec>] kasan_report_error mm/kasan/report.c:380 [inline] [<ffffffff81a7e0ec>] kasan_report mm/kasan/report.c:438 [inline] [<ffffffff81a7e0ec>] kasan_report.cold+0x8c/0x2a0 mm/kasan/report.c:422 [<ffffffff81a7dc4f>] __asan_report_load_n_noabort+0xf/0x20 mm/kasan/report.c:469 [<ffffffff82c8c00a>] bond_alb_xmit+0x153a/0x1590 drivers/net/bonding/bond_alb.c:1452 [<ffffffff82c60c74>] __bond_start_xmit drivers/net/bonding/bond_main.c:4199 [inline] [<ffffffff82c60c74>] bond_start_xmit+0x4f4/0x1570 drivers/net/bonding/bond_main.c:4224 [<ffffffff83baa558>] __netdev_start_xmit include/linux/netdevice.h:4525 [inline] [<ffffffff83baa558>] netdev_start_xmit include/linux/netdevice.h:4539 [inline] [<ffffffff83baa558>] xmit_one net/core/dev.c:3611 [inline] [<ffffffff83baa558>] dev_hard_start_xmit+0x168/0x910 net/core/dev.c:3627 [<ffffffff83bacf35>] __dev_queue_xmit+0x1f55/0x33b0 net/core/dev.c:4238 [<ffffffff83bae3a8>] dev_queue_xmit+0x18/0x20 net/core/dev.c:4278 [<ffffffff84339189>] packet_snd net/packet/af_packet.c:3226 [inline] [<ffffffff84339189>] packet_sendmsg+0x4919/0x70b0 net/packet/af_packet.c:3252 [<ffffffff83b1ac0c>] sock_sendmsg_nosec net/socket.c:673 [inline] [<ffffffff83b1ac0c>] sock_sendmsg+0x12c/0x160 net/socket.c:684 [<ffffffff83b1f5a2>] __sys_sendto+0x262/0x380 net/socket.c:1996 [<ffffffff83b1f700>] SYSC_sendto net/socket.c:2008 [inline] [<ffffffff83b1f700>] SyS_sendto+0x40/0x60 net/socket.c:2004
--- drivers/net/bonding/bond_alb.c | 44 +++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-)
drivers/net/bonding/bond_alb.c +32 -12
@@ -1403,26 +1403,31 @@ int bond_alb_xmit(struct sk_buff *skb, sbool do_tx_balance = true;u32 hash_index =0 ;const u8 *hash_start =NULL ; -struct ipv6hdr *ip6hdr;skb_reset_mac_header (skb); eth_data =eth_hdr (skb);switch (ntohs (skb->protocol)) {case ETH_P_IP : { -const struct iphdr *iph =ip_hdr (skb); +const struct iphdr *iph;if (ether_addr_equal_64bits (eth_data->h_dest, mac_bcast) || - (iph->daddr == ip_bcast) || - (iph->protocol ==IPPROTO_IGMP )) { + (!pskb_network_may_pull (skb,sizeof (*iph)))) { + do_tx_balance = false; +break ; + } + iph =ip_hdr (skb); +if (iph->daddr == ip_bcast || iph->protocol ==IPPROTO_IGMP ) { do_tx_balance = false;break ; } hash_start = (char *)&(iph->daddr); hash_size =sizeof (iph->daddr); - }break ; -case ETH_P_IPV6 : + } +case ETH_P_IPV6 : { +const struct ipv6hdr *ip6hdr; +/* IPv6 doesn't really use broadcast mac address, but leave * that here just in case. */
@@ -1439,7 +1444,11 @@ int bond_alb_xmit(struct sk_buff *skb, sbreak ; } -/* Additianally, DAD probes should not be tx-balanced as that +if (!pskb_network_may_pull (skb,sizeof (*ip6hdr))) { + do_tx_balance = false; +break ; + } +/* Additionally, DAD probes should not be tx-balanced as that * will lead to false positives for duplicate addresses and * prevent address configuration from working. */
@@ -1449,17 +1458,26 @@ int bond_alb_xmit(struct sk_buff *skb, sbreak ; } - hash_start = (char *)&(ipv6_hdr (skb)->daddr); - hash_size =sizeof (ipv6_hdr (skb)->daddr); + hash_start = (char *)&ip6hdr->daddr; + hash_size =sizeof (ip6hdr->daddr);break ; -case ETH_P_IPX : -if (ipx_hdr (skb)->ipx_checksum !=IPX_NO_CHECKSUM ) { + } +case ETH_P_IPX : { +const struct ipxhdr *ipxhdr; + +if (pskb_network_may_pull (skb,sizeof (*ipxhdr))) { + do_tx_balance = false; +break ; + } + ipxhdr = (struct ipxhdr *)skb_network_header (skb); + +if (ipxhdr->ipx_checksum !=IPX_NO_CHECKSUM ) {/* something is wrong with this packet */ do_tx_balance = false;break ; } -if (ipx_hdr (skb)->ipx_type !=IPX_TYPE_NCP ) { +if (ipxhdr->ipx_type !=IPX_TYPE_NCP ) {/* The only protocol worth balancing in * this family since it has an "ARP" like * mechanism
@@ -1468,9 +1486,11 @@ int bond_alb_xmit(struct sk_buff *skb, sbreak ; } + eth_data =eth_hdr (skb); hash_start = (char *)eth_data->h_dest; hash_size =ETH_ALEN ;break ; + }case ETH_P_ARP : do_tx_balance = false;if (bond_info->rlb_enabled)
Greg Kroah-Hartman
maintainerPATCH 118/173 ext4: fix deadlock allocating crypto bounce page from mempool
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
[ Upstream commit 547c556f4db7c09447ecf5f833ab6aaae0c5ab58 ]
ext4_writepages() on an encrypted file has to encrypt the data, but it can't modify the pagecache pages in-place, so it encrypts the data into bounce pages and writes those instead. All bounce pages are allocated from a mempool using GFP_NOFS.
This is not correct use of a mempool, and it can deadlock. This is because GFP_NOFS includes __GFP_DIRECT_RECLAIM, which enables the "never fail" mode for mempool_alloc() where a failed allocation will fall back to waiting for one of the preallocated elements in the pool.
But since this mode is used for all a bio's pages and not just the first, it can deadlock waiting for pages already in the bio to be freed.
This deadlock can be reproduced by patching mempool_alloc() to pretend that pool->alloc() always fails (so that it always falls back to the preallocations), and then creating an encrypted file of size > 128 KiB.
Fix it by only using GFP_NOFS for the first page in the bio. For subsequent pages just use GFP_NOWAIT, and if any of those fail, just submit the bio and start a new one.
This will need to be fixed in f2fs too, but that's less straightforward.
--- fs/ext4/page-io.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-)
fs/ext4/page-io.c +14 -5
@@ -481,17 +481,26 @@ int ext4_bio_write_page(struct ext4_io_submit *io, nr_to_submit) {gfp_t gfp_flags =GFP_NOFS ; +/* +* Since bounce page allocation uses a mempool, we can only use +* a waiting mask (i.e. request guaranteed allocation) on the +* first page of the bio. Otherwise it can deadlock. +*/ +if (io->io_bio) + gfp_flags =GFP_NOWAIT | __GFP_NOWARN; retry_encrypt: data_page =fscrypt_encrypt_page (inode, page,PAGE_SIZE ,0 , page->index, gfp_flags);if (IS_ERR (data_page)) { ret =PTR_ERR (data_page); -if (ret == -ENOMEM && wbc->sync_mode ==WB_SYNC_ALL ) { -if (io->io_bio) { +if (ret == -ENOMEM && + (io->io_bio || wbc->sync_mode ==WB_SYNC_ALL )) { + gfp_flags =GFP_NOFS ; +if (io->io_bio)ext4_io_submit (io); -congestion_wait (BLK_RW_ASYNC ,HZ /50 ); - } - gfp_flags |= __GFP_NOFAIL; +else + gfp_flags |= __GFP_NOFAIL; +congestion_wait (BLK_RW_ASYNC ,HZ /50 ); goto retry_encrypt; } data_page =NULL ;
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 119/173 btrfs: Get rid of the confusing btrfs_file_extent_inline_len
In reply to Greg Kroah-HartmanFrom: Qu Wenruo <[email protected]>
[ Upstream commit e41ca5897489b1c18af75ff0cc8f5c80260b3281 ]
We used to call btrfs_file_extent_inline_len() to get the uncompressed data size of an inlined extent.
However this function is hiding evil, for compressed extent, it has no choice but to directly read out ram_bytes from btrfs_file_extent_item. While for uncompressed extent, it uses item size to calculate the real data size, and ignoring ram_bytes completely.
In fact, for corrupted ram_bytes, due to above behavior kernel btrfs_print_leaf() can't even print correct ram_bytes to expose the bug.
Since we have the tree-checker to verify all EXTENT_DATA, such mismatch can be detected pretty easily, thus we can trust ram_bytes without the evil btrfs_file_extent_inline_len().
--- fs/btrfs/ctree.h | 26 -------------------------- fs/btrfs/file-item.c | 2 +- fs/btrfs/file.c | 3 +-- fs/btrfs/inode.c | 12 ++++++------ fs/btrfs/print-tree.c | 4 ++-- fs/btrfs/send.c | 17 +++++++---------- fs/btrfs/tree-log.c | 12 ++++-------- include/trace/events/btrfs.h | 2 +- 8 files changed, 22 insertions(+), 56 deletions(-)
fs/btrfs/ctree.h +0 -26
@@ -2408,32 +2408,6 @@ static inline u32 btrfs_file_extent_inline_item_len(return btrfs_item_size (eb, e) -BTRFS_FILE_EXTENT_INLINE_DATA_START ; } -/* this returns the number of file bytes represented by the inline item. -* If an item is compressed, this is the uncompressed size -*/ -static inline u32 btrfs_file_extent_inline_len (const struct extent_buffer *eb, -int slot, -const struct btrfs_file_extent_item *fi) -{ -struct btrfs_map_token token; - -btrfs_init_map_token (&token); -/* -* return the space used on disk if this item isn't -* compressed or encoded -*/ -if (btrfs_token_file_extent_compression (eb, fi, &token) ==0 && -btrfs_token_file_extent_encryption (eb, fi, &token) ==0 && -btrfs_token_file_extent_other_encoding (eb, fi, &token) ==0 ) { -return btrfs_file_extent_inline_item_len (eb, -btrfs_item_nr (slot)); - } - -/* otherwise use the ram bytes field */ -return btrfs_token_file_extent_ram_bytes (eb, fi, &token); -} - -/* btrfs_dev_stats_item */ static inline u64 btrfs_dev_stats_value(const struct extent_buffer *eb, const struct btrfs_dev_stats_item *ptr,
fs/btrfs/file-item.c +1 -1
@@ -955,7 +955,7 @@ void btrfs_extent_item_to_extent_map(struct btrfs_inode *inode,btrfs_file_extent_num_bytes (leaf, fi); }else if (type ==BTRFS_FILE_EXTENT_INLINE ) {size_t size; - size =btrfs_file_extent_inline_len (leaf, slot, fi); + size =btrfs_file_extent_ram_bytes (leaf, fi); extent_end =ALIGN (extent_start + size, fs_info->sectorsize); }
fs/btrfs/file.c +1 -2
@@ -784,8 +784,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,btrfs_file_extent_num_bytes (leaf, fi); }else if (extent_type ==BTRFS_FILE_EXTENT_INLINE ) { extent_end = key.offset + -btrfs_file_extent_inline_len (leaf, - path->slots[0 ], fi); +btrfs_file_extent_ram_bytes (leaf, fi); }else {/* can't happen */ BUG ();
fs/btrfs/inode.c +6 -6
@@ -1476,8 +1476,7 @@ static noinline int run_delalloc_nocow(struct inode *inode, nocow =1 ; }else if (extent_type ==BTRFS_FILE_EXTENT_INLINE ) { extent_end = found_key.offset + -btrfs_file_extent_inline_len (leaf, - path->slots[0 ], fi); +btrfs_file_extent_ram_bytes (leaf, fi); extent_end =ALIGN (extent_end, fs_info->sectorsize); }else {
@@ -4651,8 +4650,8 @@ int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,BTRFS_I (inode), leaf, fi, found_key.offset); }else if (extent_type ==BTRFS_FILE_EXTENT_INLINE ) { - item_end +=btrfs_file_extent_inline_len (leaf, - path->slots[0 ], fi); + item_end +=btrfs_file_extent_ram_bytes (leaf, + fi); trace_btrfs_truncate_show_fi_inline( BTRFS_I(inode), leaf, fi, path->slots[0],
@@ -7167,7 +7166,8 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode, extent_start); }else if (found_type ==BTRFS_FILE_EXTENT_INLINE ) {size_t size; - size =btrfs_file_extent_inline_len (leaf, path->slots[0 ], item); + + size =btrfs_file_extent_ram_bytes (leaf, item); extent_end =ALIGN (extent_start + size, fs_info->sectorsize);
@@ -7218,7 +7218,7 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,if (new_inline) goto out; - size =btrfs_file_extent_inline_len (leaf, path->slots[0 ], item); + size =btrfs_file_extent_ram_bytes (leaf, item); extent_offset =page_offset (page) + pg_offset - extent_start; copy_size =min_t (u64,PAGE_SIZE - pg_offset, size - extent_offset);
fs/btrfs/print-tree.c +2 -2
@@ -259,8 +259,8 @@ void btrfs_print_leaf(struct extent_buffer *l) struct btrfs_file_extent_item);if (btrfs_file_extent_type (l, fi) ==BTRFS_FILE_EXTENT_INLINE ) { -pr_info ("\t\tinline extent data size %u\n" , -btrfs_file_extent_inline_len (l, i, fi)); +pr_info ("\t\tinline extent data size %llu\n" , +btrfs_file_extent_ram_bytes (l, fi));break ; } pr_info("\t\textent data disk bytenr %llu nr %llu\n",
fs/btrfs/send.c +7 -10
@@ -1545,7 +1545,7 @@ static int read_symlink(struct btrfs_root *root,BUG_ON (compression); off =btrfs_file_extent_inline_start (ei); - len =btrfs_file_extent_inline_len (path->nodes[0 ], path->slots[0 ], ei); + len =btrfs_file_extent_ram_bytes (path->nodes[0 ], ei); ret =fs_path_add_from_extent_buffer (dest, path->nodes[0 ], off, len);
@@ -5195,7 +5195,7 @@ static int clone_range(struct send_ctx *sctx, ei = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); type =btrfs_file_extent_type (leaf, ei);if (type ==BTRFS_FILE_EXTENT_INLINE ) { - ext_len =btrfs_file_extent_inline_len (leaf, slot, ei); + ext_len =btrfs_file_extent_ram_bytes (leaf, ei); ext_len =PAGE_ALIGN (ext_len); }else { ext_len =btrfs_file_extent_num_bytes (leaf, ei);
@@ -5271,8 +5271,7 @@ static int send_write_or_clone(struct send_ctx *sctx, struct btrfs_file_extent_item); type =btrfs_file_extent_type (path->nodes[0 ], ei);if (type ==BTRFS_FILE_EXTENT_INLINE ) { - len =btrfs_file_extent_inline_len (path->nodes[0 ], - path->slots[0 ], ei); + len =btrfs_file_extent_ram_bytes (path->nodes[0 ], ei);/* * it is possible the inline item won't cover the whole page, * but there may be items after this page. Make
@@ -5405,7 +5404,7 @@ static int is_extent_unchanged(struct send_ctx *sctx, }if (right_type ==BTRFS_FILE_EXTENT_INLINE ) { - right_len =btrfs_file_extent_inline_len (eb, slot, ei); + right_len =btrfs_file_extent_ram_bytes (eb, ei); right_len =PAGE_ALIGN (right_len); }else { right_len =btrfs_file_extent_num_bytes (eb, ei);
@@ -5526,8 +5525,7 @@ static int get_last_extent(struct send_ctx *sctx, u64 offset) struct btrfs_file_extent_item); type =btrfs_file_extent_type (path->nodes[0 ], fi);if (type ==BTRFS_FILE_EXTENT_INLINE ) { -u64 size =btrfs_file_extent_inline_len (path->nodes[0 ], - path->slots[0 ], fi); +u64 size =btrfs_file_extent_ram_bytes (path->nodes[0 ], fi); extent_end =ALIGN (key.offset + size, sctx->send_root->fs_info->sectorsize); }else {
@@ -5590,7 +5588,7 @@ static int range_is_hole_in_parent(struct send_ctx *sctx, fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item);if (btrfs_file_extent_type (leaf, fi) ==BTRFS_FILE_EXTENT_INLINE ) { -u64 size =btrfs_file_extent_inline_len (leaf, slot, fi); +u64 size =btrfs_file_extent_ram_bytes (leaf, fi); extent_end =ALIGN (key.offset + size, root->fs_info->sectorsize);
@@ -5636,8 +5634,7 @@ static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path, struct btrfs_file_extent_item); type =btrfs_file_extent_type (path->nodes[0 ], fi);if (type ==BTRFS_FILE_EXTENT_INLINE ) { -u64 size =btrfs_file_extent_inline_len (path->nodes[0 ], - path->slots[0 ], fi); +u64 size =btrfs_file_extent_ram_bytes (path->nodes[0 ], fi); extent_end =ALIGN (key->offset + size, sctx->send_root->fs_info->sectorsize); }else {
fs/btrfs/tree-log.c +4 -8
@@ -619,7 +619,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,if (btrfs_file_extent_disk_bytenr (eb, item) ==0 ) nbytes =0 ; }else if (found_type ==BTRFS_FILE_EXTENT_INLINE ) { - size =btrfs_file_extent_inline_len (eb, slot, item); + size =btrfs_file_extent_ram_bytes (eb, item); nbytes =btrfs_file_extent_ram_bytes (eb, item); extent_end =ALIGN (start + size, fs_info->sectorsize);
@@ -3943,9 +3943,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, struct btrfs_file_extent_item);if (btrfs_file_extent_type (src, extent) ==BTRFS_FILE_EXTENT_INLINE ) { - len =btrfs_file_extent_inline_len (src, - src_path->slots[0 ], - extent); + len =btrfs_file_extent_ram_bytes (src, extent); *last_extent =ALIGN (key.offset + len, fs_info->sectorsize); }else {
@@ -4010,7 +4008,7 @@ static noinline int copy_items(struct btrfs_trans_handle *trans, extent = btrfs_item_ptr(src, i, struct btrfs_file_extent_item);if (btrfs_file_extent_type (src, extent) ==BTRFS_FILE_EXTENT_INLINE ) { - len =btrfs_file_extent_inline_len (src, i, extent); + len =btrfs_file_extent_ram_bytes (src, extent); extent_end =ALIGN (key.offset + len, fs_info->sectorsize); }else {
@@ -4730,9 +4728,7 @@ static int btrfs_log_trailing_hole(struct btrfs_trans_handle *trans, if (btrfs_file_extent_type(leaf, extent) == BTRFS_FILE_EXTENT_INLINE) { - len = btrfs_file_extent_inline_len(leaf, - path->slots[0], - extent); + len = btrfs_file_extent_ram_bytes(leaf, extent); ASSERT(len == i_size || (len == fs_info->sectorsize && btrfs_file_extent_compression(leaf, extent) !=
include/trace/events/btrfs.h +1 -1
@@ -325,7 +325,7 @@ DECLARE_EVENT_CLASS( __entry->extent_type =btrfs_file_extent_type (l, fi); __entry->compression =btrfs_file_extent_compression (l, fi); __entry->extent_start = start; - __entry->extent_end = (start +btrfs_file_extent_inline_len (l, slot, fi)); + __entry->extent_end = (start +btrfs_file_extent_ram_bytes (l, fi)); ), TP_printk_btrfs(
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 88/173 KVM: x86: Protect MSR-based index computations in fixed_msr_to_seg_unit() from Spectre-v1/L1TF attacks
In reply to Greg Kroah-HartmanFrom: Marios Pomonis <[email protected]>
commit 25a5edea71b7c154b6a0b8cec14c711cafa31d26 upstream.
This fixes a Spectre-v1/L1TF vulnerability in fixed_msr_to_seg_unit(). This function contains index computations based on the (attacker-controlled) MSR number.
--- arch/x86/kvm/mtrr.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
arch/x86/kvm/mtrr.c +6 -2
@@ -202,11 +202,15 @@ static bool fixed_msr_to_seg_unit(u32 msbreak ; case MSR_MTRRfix16K_80000 ... MSR_MTRRfix16K_A0000: *seg =1 ; - *unit = msr - MSR_MTRRfix16K_80000; + *unit =array_index_nospec ( + msr - MSR_MTRRfix16K_80000, + MSR_MTRRfix16K_A0000 - MSR_MTRRfix16K_80000 +1 );break ; case MSR_MTRRfix4K_C0000 ... MSR_MTRRfix4K_F8000: *seg =2 ; - *unit = msr - MSR_MTRRfix4K_C0000; + *unit =array_index_nospec ( + msr - MSR_MTRRfix4K_C0000, + MSR_MTRRfix4K_F8000 - MSR_MTRRfix4K_C0000 +1 );break ;default :return false;
Greg Kroah-Hartman
maintainerPATCH 96/173 scsi: ufs: Recheck bkops level if bkops is disabled
In reply to Greg Kroah-HartmanFrom: Asutosh Das <[email protected]>
commit 24366c2afbb0539fb14eff330d4e3a5db5c0a3ef upstream.
bkops level should be rechecked upon receiving an exception. Currently the level is being cached and never updated.
Update bkops each time the level is checked. Also do not use the cached bkops level value if it is disabled and then enabled.
--- drivers/scsi/ufs/ufshcd.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/scsi/ufs/ufshcd.c +3 -0
@@ -4812,6 +4812,7 @@ static int ufshcd_disable_auto_bkops(str hba->auto_bkops_enabled = false;trace_ufshcd_auto_bkops_state (dev_name (hba->dev),"Disabled" ); + hba->is_urgent_bkops_lvl_checked = false; out:return err; }
@@ -4836,6 +4837,7 @@ static void ufshcd_force_reset_auto_bkop hba->ee_ctrl_mask &= ~MASK_EE_URGENT_BKOPS ;ufshcd_disable_auto_bkops (hba); } + hba->is_urgent_bkops_lvl_checked = false; }static inline int ufshcd_get_bkops_status (struct ufs_hba *hba,u32 *status)
@@ -4882,6 +4884,7 @@ static int ufshcd_bkops_ctrl(struct ufs_ err =ufshcd_enable_auto_bkops (hba); else err =ufshcd_disable_auto_bkops (hba); + hba->urgent_bkops_lvl = curr_status; out:return err; }
Greg Kroah-Hartman
maintainerPATCH 95/173 scsi: qla4xxx: Adjust indentation in qla4xxx_mem_free
In reply to Greg Kroah-HartmanFrom: Nathan Chancellor <[email protected]>
commit aa8679736a82386551eb9f3ea0e6ebe2c0e99104 upstream.
Clang warns:
../drivers/scsi/qla4xxx/ql4_os.c:4148:3: warning: misleading indentation; statement is not part of the previous 'if' [-Wmisleading-indentation]
if (ha->fw_dump)
^
../drivers/scsi/qla4xxx/ql4_os.c:4144:2: note: previous statement is
here
if (ha->queues)
^1 warning generated.
This warning occurs because there is a space after the tab on this line. Remove it so that the indentation is consistent with the Linux kernel coding style and clang no longer warns.
--- drivers/scsi/qla4xxx/ql4_os.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/scsi/qla4xxx/ql4_os.c +1 -1
@@ -4150,7 +4150,7 @@ static void qla4xxx_mem_free(struct scsidma_free_coherent (&ha->pdev->dev, ha->queues_len, ha->queues, ha->queues_dma); -if (ha->fw_dump) +if (ha->fw_dump)vfree (ha->fw_dump); ha->queues_len =0 ;
Greg Kroah-Hartman
maintainerPATCH 105/173 IB/core: Fix ODP get user pages flow
In reply to Greg Kroah-HartmanFrom: Yishai Hadas <[email protected]>
commit d07de8bd1709a80a282963ad7b2535148678a9e4 upstream.
The nr_pages argument of get_user_pages_remote() should always be in terms of the system page size, not the MR page size. Use PAGE_SIZE instead of umem_odp->page_shift.
--- drivers/infiniband/core/umem_odp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/core/umem_odp.c +1 -1
@@ -637,7 +637,7 @@ int ib_umem_odp_map_dma_pages(struct ib_while (bcnt >0 ) {const size_t gup_num_pages =min_t (size_t, - (bcnt +BIT (page_shift) -1 ) >> page_shift, +ALIGN (bcnt,PAGE_SIZE ) /PAGE_SIZE ,PAGE_SIZE /sizeof (struct page *));down_read (&owning_mm->mmap_sem);
Greg Kroah-Hartman
maintainerPATCH 104/173 IB/mlx5: Fix outstanding_pi index for GSI qps
In reply to Greg Kroah-HartmanFrom: Prabhath Sajeepa <[email protected]>
commit b5671afe5e39ed71e94eae788bacdcceec69db09 upstream.
Commit b0ffeb537f3a ("IB/mlx5: Fix iteration overrun in GSI qps") changed the way outstanding WRs are tracked for the GSI QP. But the fix did not cover the case when a call to ib_post_send() fails and updates index to track outstanding.
Since the prior commmit outstanding_pi should not be bounded otherwise the loop generate_completions() will fail.
--- drivers/infiniband/hw/mlx5/gsi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/infiniband/hw/mlx5/gsi.c +1 -2
@@ -507,8 +507,7 @@ int mlx5_ib_gsi_post_send(struct ib_qp * ret =ib_post_send (tx_qp, &cur_wr.wr, bad_wr);if (ret) {/* Undo the effect of adding the outstanding wr */ - gsi->outstanding_pi = (gsi->outstanding_pi -1 ) % - gsi->cap.max_send_wr; + gsi->outstanding_pi--; goto err; }spin_unlock_irqrestore (&gsi->lock, flags);
Greg Kroah-Hartman
maintainerPATCH 102/173 net: smc911x: Adjust indentation in smc911x_phy_configure
In reply to Greg Kroah-HartmanFrom: Nathan Chancellor <[email protected]>
commit 5c61e223004b3b5c3f1dd25718e979bc17a3b12d upstream.
Clang warns:
../drivers/net/ethernet/smsc/smc911x.c:939:3: warning: misleading indentation; statement is not part of the previous 'if' [-Wmisleading-indentation]
if (!lp->ctl_rfduplx)
^
../drivers/net/ethernet/smsc/smc911x.c:936:2: note: previous statement
is here
if (lp->ctl_rspeed != 100)
^1 warning generated.
This warning occurs because there is a space after the tab on this line. Remove it so that the indentation is consistent with the Linux kernel coding style and clang no longer warns.
--- drivers/net/ethernet/smsc/smc911x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/smsc/smc911x.c +1 -1
@@ -948,7 +948,7 @@ static void smc911x_phy_configure(structif (lp->ctl_rspeed !=100 ) my_ad_caps &= ~(ADVERTISE_100BASE4 |ADVERTISE_100FULL |ADVERTISE_100HALF ); -if (!lp->ctl_rfduplx) +if (!lp->ctl_rfduplx) my_ad_caps &= ~(ADVERTISE_100FULL |ADVERTISE_10FULL );/* Update our Auto-Neg Advertisement Register */
Greg Kroah-Hartman
maintainerPATCH 101/173 ppp: Adjust indentation into ppp_async_input
In reply to Greg Kroah-HartmanFrom: Nathan Chancellor <[email protected]>
commit 08cbc75f96029d3092664213a844a5e25523aa35 upstream.
Clang warns:
../drivers/net/ppp/ppp_async.c:877:6: warning: misleading indentation; statement is not part of the previous 'if' [-Wmisleading-indentation]
ap->rpkt = skb;
^
../drivers/net/ppp/ppp_async.c:875:5: note: previous statement is here
if (!skb)
^1 warning generated.
This warning occurs because there is a space before the tab on this line. Clean up this entire block's indentation so that it is consistent with the Linux kernel coding style and clang no longer warns.
--- drivers/net/ppp/ppp_async.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
drivers/net/ppp/ppp_async.c +9 -9
@@ -878,15 +878,15 @@ ppp_async_input(struct asyncppp *ap, con skb =dev_alloc_skb (ap->mru +PPP_HDRLEN +2 );if (!skb) goto nomem; - ap->rpkt = skb; - } -if (skb->len ==0 ) { -/* Try to get the payload 4-byte aligned. -* This should match the -* PPP_ALLSTATIONS/PPP_UI/compressed tests in -* process_input_packet, but we do not have -* enough chars here to test buf[1] and buf[2]. -*/ + ap->rpkt = skb; + } +if (skb->len ==0 ) { +/* Try to get the payload 4-byte aligned. +* This should match the +* PPP_ALLSTATIONS/PPP_UI/compressed tests in +* process_input_packet, but we do not have +* enough chars here to test buf[1] and buf[2]. +*/ if (buf[0 ] !=PPP_ALLSTATIONS )skb_reserve (skb,2 + (buf[0 ] &1 )); }
Greg Kroah-Hartman
maintainerPATCH 99/173 powerpc/44x: Adjust indentation in ibm4xx_denali_fixup_memsize
In reply to Greg Kroah-HartmanFrom: Nathan Chancellor <[email protected]>
commit c3aae14e5d468d18dbb5d7c0c8c7e2968cc14aad upstream.
Clang warns:
../arch/powerpc/boot/4xx.c:231:3: warning: misleading indentation; statement is not part of the previous 'else' [-Wmisleading-indentation]
val = SDRAM0_READ(DDR0_42);
^
../arch/powerpc/boot/4xx.c:227:2: note: previous statement is here
else
^This is because there is a space at the beginning of this line; remove it so that the indentation is consistent according to the Linux kernel coding style and clang no longer warns.
--- arch/powerpc/boot/4xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/boot/4xx.c +1 -1
@@ -232,7 +232,7 @@ void ibm4xx_denali_fixup_memsize(void) dpath =8 ;/* 64 bits */ /* get address pins (rows) */ - val =SDRAM0_READ (DDR0_42 ); + val =SDRAM0_READ (DDR0_42 ); row =DDR_GET_VAL (val,DDR_APIN ,DDR_APIN_SHIFT );if (row > max_row)
Greg Kroah-Hartman
maintainerPATCH 98/173 ext2: Adjust indentation in ext2_fill_super
In reply to Greg Kroah-HartmanFrom: Nathan Chancellor <[email protected]>
commit d9e9866803f7b6c3fdd35d345e97fb0b2908bbbc upstream.
Clang warns:
../fs/ext2/super.c:1076:3: warning: misleading indentation; statement is not part of the previous 'if' [-Wmisleading-indentation]
sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) -
^
../fs/ext2/super.c:1074:2: note: previous statement is here
if (EXT2_BLOCKS_PER_GROUP(sb) == 0)
^1 warning generated.
This warning occurs because there is a space before the tab on this line. Remove it so that the indentation is consistent with the Linux kernel coding style and clang no longer warns.
--- fs/ext2/super.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
fs/ext2/super.c +3 -3
@@ -1077,9 +1077,9 @@ static int ext2_fill_super(struct super_if (EXT2_BLOCKS_PER_GROUP (sb) ==0 ) goto cantfind_ext2; - sbi->s_groups_count = ((le32_to_cpu (es->s_blocks_count) - -le32_to_cpu (es->s_first_data_block) -1 ) - /EXT2_BLOCKS_PER_GROUP (sb)) +1 ; + sbi->s_groups_count = ((le32_to_cpu (es->s_blocks_count) - +le32_to_cpu (es->s_first_data_block) -1 ) + /EXT2_BLOCKS_PER_GROUP (sb)) +1 ; db_count = (sbi->s_groups_count +EXT2_DESC_PER_BLOCK (sb) -1 ) /EXT2_DESC_PER_BLOCK (sb); sbi->s_group_desc =kmalloc (db_count *sizeof (struct buffer_head *),GFP_KERNEL );
Greg Kroah-Hartman
maintainerPATCH 89/173 KVM: PPC: Book3S HV: Uninit vCPU if vcore creation fails
In reply to Greg Kroah-HartmanFrom: Sean Christopherson <[email protected]>
commit 1a978d9d3e72ddfa40ac60d26301b154247ee0bc upstream.
Call kvm_vcpu_uninit() if vcore creation fails to avoid leaking any resources allocated by kvm_vcpu_init(), i.e. the vcpu->run page.
--- arch/powerpc/kvm/book3s_hv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
arch/powerpc/kvm/book3s_hv.c +3 -1
@@ -1997,7 +1997,7 @@ static struct kvm_vcpu *kvmppc_core_vcpumutex_unlock (&kvm->lock);if (!vcore) - goto free_vcpu; + goto uninit_vcpu;spin_lock (&vcore->lock); ++vcore->num_threads;
@@ -2014,6 +2014,8 @@ static struct kvm_vcpu *kvmppc_core_vcpureturn vcpu; +uninit_vcpu: +kvm_vcpu_uninit (vcpu); free_vcpu:kmem_cache_free (kvm_vcpu_cache, vcpu); out:
Greg Kroah-Hartman
maintainerPATCH 78/173 KVM: x86: Refactor picdev_write() to prevent Spectre-v1/L1TF attacks
In reply to Greg Kroah-HartmanFrom: Marios Pomonis <[email protected]>
commit 14e32321f3606e4b0970200b6e5e47ee6f1e6410 upstream.
This fixes a Spectre-v1/L1TF vulnerability in picdev_write(). It replaces index computations based on the (attacked-controlled) port number with constants through a minor refactoring.
--- arch/x86/kvm/i8259.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
arch/x86/kvm/i8259.c +5 -1
@@ -460,10 +460,14 @@ static int picdev_write(struct kvm_pic *switch (addr) {case 0x20 :case 0x21 : +pic_lock (s); +pic_ioport_write (&s->pics[0 ], addr, data); +pic_unlock (s); +break ;case 0xa0 :case 0xa1 :pic_lock (s); -pic_ioport_write (&s->pics[addr >>7 ], addr, data); +pic_ioport_write (&s->pics[1 ], addr, data);pic_unlock (s);break ;case 0x4d0 :
Greg Kroah-Hartman
maintainerPATCH 77/173 xen/balloon: Support xend-based toolstack take two
In reply to Greg Kroah-HartmanFrom: Juergen Gross <[email protected]>
commit eda4eabf86fd6806eaabc23fb90dd056fdac037b upstream.
Commit 3aa6c19d2f38be ("xen/balloon: Support xend-based toolstack") tried to fix a regression with running on rather ancient Xen versions. Unfortunately the fix was based on the assumption that xend would just use another Xenstore node, but in reality only some downstream versions of xend are doing that. The upstream xend does not write that Xenstore node at all, so the problem must be fixed in another way.
The easiest way to achieve that is to fall back to the behavior before commit 96edd61dcf4436 ("xen/balloon: don't online new memory initially") in case the static memory maximum can't be read.
This is achieved by setting static_max to the current number of memory pages known by the system resulting in target_diff becoming zero.
--- drivers/xen/xen-balloon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/xen/xen-balloon.c +1 -1
@@ -82,7 +82,7 @@ static void watch_target(struct xenbus_w "%llu", &static_max) == 1)) static_max >>=PAGE_SHIFT -10 ; else - static_max = new_target; + static_max = balloon_stats.current_pages; target_diff = (xen_pv_domain () ||xen_initial_domain ()) ?0 : static_max - balloon_stats.target_pages;
Greg Kroah-Hartman
maintainerPATCH 76/173 tools/kvm_stat: Fix kvm_exit filter name
In reply to Greg Kroah-HartmanFrom: Gavin Shan <[email protected]>
commit 5fcf3a55a62afb0760ccb6f391d62f20bce4a42f upstream.
The filter name is fixed to "exit_reason" for some kvm_exit events, no matter what architect we have. Actually, the filter name ("exit_reason") is only applicable to x86, meaning it's broken on other architects including aarch64.
This fixes the issue by providing various kvm_exit filter names, depending on architect we're on. Afterwards, the variable filter name is picked and applied through ioctl(fd, SET_FILTER).
--- tools/kvm/kvm_stat/kvm_stat | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
tools/kvm/kvm_stat/kvm_stat +6 -2
@@ -261,6 +261,7 @@ class ArchX86(Arch): def __init__(self, exit_reasons): self.sc_perf_evt_open = 298 self.ioctl_numbers = IOCTL_NUMBERS + self.exit_reason_field = 'exit_reason' self.exit_reasons = exit_reasons
@@ -276,6 +277,7 @@ class ArchPPC(Arch): # numbers depend on the wordsize. char_ptr_size = ctypes.sizeof(ctypes.c_char_p) self.ioctl_numbers['SET_FILTER'] = 0x80002406 | char_ptr_size << 16 + self.exit_reason_field = 'exit_nr' self.exit_reasons = {}
@@ -283,6 +285,7 @@ class ArchA64(Arch): def __init__(self): self.sc_perf_evt_open = 241 self.ioctl_numbers = IOCTL_NUMBERS + self.exit_reason_field = 'esr_ec' self.exit_reasons = AARCH64_EXIT_REASONS
@@ -290,6 +293,7 @@ class ArchS390(Arch): def __init__(self): self.sc_perf_evt_open = 331 self.ioctl_numbers = IOCTL_NUMBERS + self.exit_reason_field = None self.exit_reasons = None ARCH = Arch.get_arch()
@@ -513,8 +517,8 @@ class TracepointProvider(Provider): """ filters = {} filters['kvm_userspace_exit'] = ('reason', USERSPACE_EXIT_REASONS) - if ARCH.exit_reasons: - filters['kvm_exit'] = ('exit_reason', ARCH.exit_reasons) + if ARCH.exit_reason_field and ARCH.exit_reasons: + filters['kvm_exit'] = (ARCH.exit_reason_field, ARCH.exit_reasons) return filters def get_available_fields(self):
Greg Kroah-Hartman
maintainerPATCH 74/173 mwifiex: fix unbalanced locking in mwifiex_process_country_ie()
In reply to Greg Kroah-HartmanFrom: Brian Norris <[email protected]>
commit 65b1aae0d9d5962faccc06bdb8e91a2a0b09451c upstream.
We called rcu_read_lock(), so we need to call rcu_read_unlock() before we return.
--- drivers/net/wireless/marvell/mwifiex/sta_ioctl.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +1 -0
@@ -274,6 +274,7 @@ static int mwifiex_process_country_ie(stif (country_ie_len > (IEEE80211_COUNTRY_STRING_LEN +MWIFIEX_MAX_TRIPLET_802_11D )) { +rcu_read_unlock ();mwifiex_dbg (priv->adapter,ERROR ,"11D: country_ie_len overflow!, deauth AP\n" );return -EINVAL ;
Greg Kroah-Hartman
maintainerPATCH 73/173 iwlwifi: dont throw error when trying to remove IGTK
In reply to Greg Kroah-HartmanFrom: Luca Coelho <[email protected]>
commit 197288d5ba8a5289f22d3aeb4fca3824bfd9b4af upstream.
The IGTK keys are only removed by mac80211 after it has already removed the AP station. This causes the driver to throw an error because mac80211 is trying to remove the IGTK when the station doesn't exist anymore.
The firmware is aware that the station has been removed and can deal with it the next time we try to add an IGTK for a station, so we shouldn't try to remove the key if the station ID is IWL_MVM_INVALID_STA. Do this by removing the check for mvm_sta before calling iwl_mvm_send_sta_igtk() and check return from that function gracefully if the station ID is invalid.
--- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/net/wireless/intel/iwlwifi/mvm/sta.c +7 -3
@@ -2981,6 +2981,10 @@ static int iwl_mvm_send_sta_igtk(struct igtk_cmd.sta_id =cpu_to_le32 (sta_id);if (remove_key) { +/* This is a valid situation for IGTK */ +if (sta_id ==IWL_MVM_INVALID_STA ) +return 0 ; + igtk_cmd.ctrl_flags |=cpu_to_le32 (STA_KEY_NOT_VALID ); }else {struct ieee80211_key_seq seq;
@@ -3285,9 +3289,9 @@ int iwl_mvm_remove_sta_key(struct iwl_mvIWL_DEBUG_WEP (mvm,"mvm remove dynamic key: idx=%d sta=%d\n" , keyconf->keyidx, sta_id); -if (mvm_sta && (keyconf->cipher ==WLAN_CIPHER_SUITE_AES_CMAC || - keyconf->cipher ==WLAN_CIPHER_SUITE_BIP_GMAC_128 || - keyconf->cipher ==WLAN_CIPHER_SUITE_BIP_GMAC_256 )) +if (keyconf->cipher ==WLAN_CIPHER_SUITE_AES_CMAC || + keyconf->cipher ==WLAN_CIPHER_SUITE_BIP_GMAC_128 || + keyconf->cipher ==WLAN_CIPHER_SUITE_BIP_GMAC_256 )return iwl_mvm_send_sta_igtk (mvm, keyconf, sta_id, true);if (!__test_and_clear_bit (keyconf->hw_key_idx, mvm->fw_key_table)) {
Greg Kroah-Hartman
maintainerPATCH 87/173 KVM: x86: Protect x86_decode_insn from Spectre-v1/L1TF attacks
In reply to Greg Kroah-HartmanFrom: Marios Pomonis <[email protected]>
commit 3c9053a2cae7ba2ba73766a34cea41baa70f57f7 upstream.
This fixes a Spectre-v1/L1TF vulnerability in x86_decode_insn(). kvm_emulate_instruction() (an ancestor of x86_decode_insn()) is an exported symbol, so KVM should treat it conservatively from a security perspective.
--- arch/x86/kvm/emulate.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
arch/x86/kvm/emulate.c +8 -3
@@ -5199,10 +5199,15 @@ done_prefixes: }break ;case Escape: -if (ctxt->modrm >0xbf ) - opcode = opcode.u.esc->high[ctxt->modrm -0xc0 ]; -else +if (ctxt->modrm >0xbf ) { +size_t size =ARRAY_SIZE (opcode.u.esc->high); +u32 index =array_index_nospec ( + ctxt->modrm -0xc0 , size); + + opcode = opcode.u.esc->high[index]; + }else { opcode = opcode.u.esc->op[(ctxt->modrm >>3 ) &7 ]; + }break ;case InstrDual:if ((ctxt->modrm >>6 ) ==3 )
Greg Kroah-Hartman
maintainerPATCH 83/173 KVM: x86: Protect ioapic_write_indirect() from Spectre-v1/L1TF attacks
In reply to Greg Kroah-HartmanFrom: Marios Pomonis <[email protected]>
commit 670564559ca35b439c8d8861fc399451ddf95137 upstream.
This fixes a Spectre-v1/L1TF vulnerability in ioapic_write_indirect(). This function contains index computations based on the (attacker-controlled) IOREGSEL register.
This patch depends on patch
"KVM: x86: Protect ioapic_read_indirect() from Spectre-v1/L1TF attacks".
--- arch/x86/kvm/ioapic.c | 1 + 1 file changed, 1 insertion(+)
arch/x86/kvm/ioapic.c +1 -0
@@ -297,6 +297,7 @@ static void ioapic_write_indirect(structioapic_debug ("change redir index %x val %x\n" , index, val);if (index >=IOAPIC_NUM_PINS )return ; + index =array_index_nospec (index,IOAPIC_NUM_PINS ); e = &ioapic->redirtbl[index]; mask_before = e->fields.mask;/* Preserve read-only fields */
Greg Kroah-Hartman
maintainerPATCH 82/173 KVM: x86: Protect kvm_hv_msr_[get|set]_crash_data() from Spectre-v1/L1TF attacks
In reply to Greg Kroah-HartmanFrom: Marios Pomonis <[email protected]>
commit 8618793750071d66028584a83ed0b4fa7eb4f607 upstream.
This fixes Spectre-v1/L1TF vulnerabilities in kvm_hv_msr_get_crash_data() and kvm_hv_msr_set_crash_data().
These functions contain index computations that use the (attacker-controlled) MSR number.
--- arch/x86/kvm/hyperv.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
arch/x86/kvm/hyperv.c +6 -4
@@ -747,11 +747,12 @@ static int kvm_hv_msr_get_crash_data(str u32 index, u64 *pdata) { struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; +size_t size =ARRAY_SIZE (hv->hv_crash_param); -if (WARN_ON_ONCE (index >=ARRAY_SIZE (hv->hv_crash_param))) +if (WARN_ON_ONCE (index >= size))return -EINVAL ; - *pdata = hv->hv_crash_param[index]; + *pdata = hv->hv_crash_param[array_index_nospec (index, size)];return 0 ; }
@@ -790,11 +791,12 @@ static int kvm_hv_msr_set_crash_data(str u32 index, u64 data) {struct kvm_hv *hv = &vcpu->kvm->arch.hyperv; +size_t size =ARRAY_SIZE (hv->hv_crash_param); -if (WARN_ON_ONCE (index >=ARRAY_SIZE (hv->hv_crash_param))) +if (WARN_ON_ONCE (index >= size))return -EINVAL ; - hv->hv_crash_param[index] = data; + hv->hv_crash_param[array_index_nospec (index, size)] = data;return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 81/173 KVM: x86: Protect kvm_lapic_reg_write() from Spectre-v1/L1TF attacks
In reply to Greg Kroah-HartmanFrom: Marios Pomonis <[email protected]>
commit 4bf79cb089f6b1c6c632492c0271054ce52ad766 upstream.
This fixes a Spectre-v1/L1TF vulnerability in kvm_lapic_reg_write(). This function contains index computations based on the (attacker-controlled) MSR number.
--- arch/x86/kvm/lapic.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
arch/x86/kvm/lapic.c +9 -4
@@ -1754,15 +1754,20 @@ int kvm_lapic_reg_write(struct kvm_lapiccase APIC_LVTTHMR :case APIC_LVTPC :case APIC_LVT1 : -case APIC_LVTERR : +case APIC_LVTERR : {/* TODO: Check vector */ +size_t size; +u32 index; +if (!kvm_apic_sw_enabled (apic)) val |=APIC_LVT_MASKED ; - - val &= apic_lvt_mask[(reg -APIC_LVTT ) >>4 ]; + size =ARRAY_SIZE (apic_lvt_mask); + index =array_index_nospec ( + (reg -APIC_LVTT ) >>4 , size); + val &= apic_lvt_mask[index];kvm_lapic_set_reg (apic, reg, val); -break ; + }case APIC_LVTT :if (!kvm_apic_sw_enabled (apic))
Greg Kroah-Hartman
maintainerPATCH 79/173 KVM: x86: Refactor prefix decoding to prevent Spectre-v1/L1TF attacks
In reply to Greg Kroah-HartmanFrom: Marios Pomonis <[email protected]>
commit 125ffc5e0a56a3eded608dc51e09d5ebf72cf652 upstream.
This fixes Spectre-v1/L1TF vulnerabilities in vmx_read_guest_seg_selector(), vmx_read_guest_seg_base(), vmx_read_guest_seg_limit() and vmx_read_guest_seg_ar(). When invoked from emulation, these functions contain index computations based on the (attacker-influenced) segment value. Using constants prevents the attack.
--- arch/x86/kvm/emulate.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
arch/x86/kvm/emulate.c +14 -2
@@ -5094,16 +5094,28 @@ int x86_decode_insn(struct x86_emulate_c ctxt->ad_bytes = def_ad_bytes ^6 ;break ;case 0x26 :/* ES override */ + has_seg_override = true; + ctxt->seg_override =VCPU_SREG_ES ; +break ;case 0x2e :/* CS override */ + has_seg_override = true; + ctxt->seg_override =VCPU_SREG_CS ; +break ;case 0x36 :/* SS override */ + has_seg_override = true; + ctxt->seg_override =VCPU_SREG_SS ; +break ;case 0x3e :/* DS override */ has_seg_override = true; - ctxt->seg_override = (ctxt->b >>3 ) &3 ; + ctxt->seg_override =VCPU_SREG_DS ;break ;case 0x64 :/* FS override */ + has_seg_override = true; + ctxt->seg_override =VCPU_SREG_FS ; +break ;case 0x65 :/* GS override */ has_seg_override = true; - ctxt->seg_override = ctxt->b &7 ; + ctxt->seg_override =VCPU_SREG_GS ;break ; case 0x40 ... 0x4f: /* REX */if (mode !=X86EMUL_MODE_PROT64 )
Greg Kroah-Hartman
maintainerPATCH 70/173 NFS: Directory page cache pages need to be locked when read
In reply to Greg Kroah-HartmanFrom: Trond Myklebust <[email protected]>
commit 114de38225d9b300f027e2aec9afbb6e0def154b upstream.
When a NFS directory page cache page is removed from the page cache, its contents are freed through a call to nfs_readdir_clear_array(). To prevent the removal of the page cache entry until after we've finished reading it, we must take the page lock.
--- fs/nfs/dir.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-)
fs/nfs/dir.c +19 -11
@@ -708,8 +708,6 @@ int nfs_readdir_filler(nfs_readdir_descrstatic void cache_page_release (nfs_readdir_descriptor_t *desc) { -if (!desc->page->mapping) -nfs_readdir_clear_array (desc->page);put_page (desc->page); desc->page =NULL ; }
@@ -723,19 +721,28 @@ struct page *get_cache_page(nfs_readdir_/* * Returns 0 if desc->dir_cookie was found on page desc->page_index +* and locks the page to prevent removal from the page cache. */ static -int find_cache_page (nfs_readdir_descriptor_t *desc) +int find_and_lock_cache_page (nfs_readdir_descriptor_t *desc) {int res; desc->page =get_cache_page (desc);if (IS_ERR (desc->page))return PTR_ERR (desc->page); - - res =nfs_readdir_search_array (desc); + res =lock_page_killable (desc->page);if (res !=0 ) -cache_page_release (desc); + goto error; + res = -EAGAIN ; +if (desc->page->mapping !=NULL ) { + res =nfs_readdir_search_array (desc); +if (res ==0 ) +return 0 ; + } +unlock_page (desc->page); +error: +cache_page_release (desc);return res; }
@@ -750,7 +757,7 @@ int readdir_search_pagecache(nfs_readdir desc->last_cookie =0 ; }do { - res =find_cache_page (desc); + res =find_and_lock_cache_page (desc); }while (res == -EAGAIN );return res; }
@@ -789,7 +796,6 @@ int nfs_do_filldir(nfs_readdir_descripto desc->eof =1 ;kunmap (desc->page); -cache_page_release (desc);dfprintk (DIRCACHE ,"NFS: nfs_do_filldir() filling ended @ cookie %Lu; returning = %d\n" , (unsigned long long )*desc->dir_cookie, res);return res;
@@ -835,13 +841,13 @@ int uncached_readdir(nfs_readdir_descrip status =nfs_do_filldir (desc); + out_release: +nfs_readdir_clear_array (desc->page); +cache_page_release (desc); out:dfprintk (DIRCACHE ,"NFS: %s: returns %d\n" , __func__, status);return status; - out_release: -cache_page_release (desc); - goto out; }/* The file offset position represents the dirent entry number. A
@@ -906,6 +912,8 @@ static int nfs_readdir(struct file *filebreak ; res =nfs_do_filldir (desc); +unlock_page (desc->page); +cache_page_release (desc);if (res <0 )break ; }while (!desc->eof);
Greg Kroah-Hartman
maintainerPATCH 49/173 f2fs: choose hardlimit when softlimit is larger than hardlimit in f2fs_statfs_project()
In reply to Greg Kroah-HartmanFrom: Chengguang Xu <[email protected]>
commit 909110c060f22e65756659ec6fa957ae75777e00 upstream.
Setting softlimit larger than hardlimit seems meaningless for disk quota but currently it is allowed. In this case, there may be a bit of comfusion for users when they run df comamnd to directory which has project quota.
For example, we set 20M softlimit and 10M hardlimit of block usage limit for project quota of test_dir(project id 123).
[root@hades f2fs]# repquota -P -a
--- fs/f2fs/super.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-)
fs/f2fs/super.c +14 -6
@@ -912,9 +912,13 @@ static int f2fs_statfs_project(struct sureturn PTR_ERR (dquot);spin_lock (&dq_data_lock); - limit = (dquot->dq_dqb.dqb_bsoftlimit ? - dquot->dq_dqb.dqb_bsoftlimit : - dquot->dq_dqb.dqb_bhardlimit) >> sb->s_blocksize_bits; + limit =0 ; +if (dquot->dq_dqb.dqb_bsoftlimit) + limit = dquot->dq_dqb.dqb_bsoftlimit; +if (dquot->dq_dqb.dqb_bhardlimit && + (!limit || dquot->dq_dqb.dqb_bhardlimit < limit)) + limit = dquot->dq_dqb.dqb_bhardlimit; +if (limit && buf->f_blocks > limit) { curblock = dquot->dq_dqb.dqb_curspace >> sb->s_blocksize_bits; buf->f_blocks = limit;
@@ -923,9 +927,13 @@ static int f2fs_statfs_project(struct su (buf->f_blocks - curblock) : 0; } - limit = dquot->dq_dqb.dqb_isoftlimit ? - dquot->dq_dqb.dqb_isoftlimit : - dquot->dq_dqb.dqb_ihardlimit; + limit =0 ; +if (dquot->dq_dqb.dqb_isoftlimit) + limit = dquot->dq_dqb.dqb_isoftlimit; +if (dquot->dq_dqb.dqb_ihardlimit && + (!limit || dquot->dq_dqb.dqb_ihardlimit < limit)) + limit = dquot->dq_dqb.dqb_ihardlimit; +if (limit && buf->f_files > limit) { buf->f_files = limit; buf->f_ffree =
Greg Kroah-Hartman
maintainerPATCH 58/173 tracing: Annotate ftrace_graph_hash pointer with __rcu
In reply to Greg Kroah-HartmanFrom: Amol Grover <[email protected]>
[ Upstream commit 24a9729f831462b1d9d61dc85ecc91c59037243f ]
Fix following instances of sparse error kernel/trace/ftrace.c:5664:29: error: incompatible types in comparison kernel/trace/ftrace.c:5785:21: error: incompatible types in comparison kernel/trace/ftrace.c:5864:36: error: incompatible types in comparison kernel/trace/ftrace.c:5866:25: error: incompatible types in comparison
Use rcu_dereference_protected to access the __rcu annotated pointer.
--- kernel/trace/ftrace.c | 2 +- kernel/trace/trace.h | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-)
kernel/trace/ftrace.c +1 -1
@@ -5146,7 +5146,7 @@ static const struct file_operations ftrace_notrace_fops = {static DEFINE_MUTEX (graph_lock); -struct ftrace_hash *ftrace_graph_hash =EMPTY_HASH ; +struct ftrace_hash __rcu *ftrace_graph_hash =EMPTY_HASH ;struct ftrace_hash *ftrace_graph_notrace_hash =EMPTY_HASH ;enum graph_filter_type {
kernel/trace/trace.h +6 -3
@@ -868,22 +868,25 @@ extern void __trace_graph_return(struct trace_array *tr, unsigned long flags, int pc);#ifdef CONFIG_DYNAMIC_FTRACE -extern struct ftrace_hash *ftrace_graph_hash; +extern struct ftrace_hash __rcu *ftrace_graph_hash;extern struct ftrace_hash *ftrace_graph_notrace_hash;static inline int ftrace_graph_addr (struct ftrace_graph_ent *trace) {unsigned long addr = trace->func;int ret =0 ; +struct ftrace_hash *hash;preempt_disable_notrace (); -if (ftrace_hash_empty (ftrace_graph_hash)) { + hash =rcu_dereference_protected (ftrace_graph_hash, !preemptible ()); + +if (ftrace_hash_empty (hash)) { ret =1 ; goto out; } -if (ftrace_lookup_ip (ftrace_graph_hash, addr)) { +if (ftrace_lookup_ip (hash, addr)) {/* * This needs to be cleared on the return functions
Signature · 1 line
2.20.1
Greg Kroah-Hartman
maintainerPATCH 54/173 dm zoned: support zone sizes smaller than 128MiB
In reply to Greg Kroah-HartmanFrom: Dmitry Fomichev <[email protected]>
commit b39962950339912978484cdac50069258545d753 upstream.
dm-zoned is observed to log failed kernel assertions and not work correctly when operating against a device with a zone size smaller than 128MiB (e.g. 32768 bits per 4K block). The reason is that the bitmap size per zone is calculated as zero with such a small zone size. Fix this problem and also make the code related to zone bitmap management be able to handle per zone bitmaps smaller than a single block.
A dm-zoned-tools patch is required to properly format dm-zoned devices with zone sizes smaller than 128MiB.
--- drivers/md/dm-zoned-metadata.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-)
drivers/md/dm-zoned-metadata.c +14 -9
@@ -132,6 +132,7 @@ struct dmz_metadata {sector_t zone_bitmap_size;unsigned int zone_nr_bitmap_blocks; +unsigned int zone_bits_per_mblk;unsigned int nr_bitmap_blocks;unsigned int nr_map_blocks;
@@ -1165,7 +1166,10 @@ static int dmz_init_zones(struct dmz_met/* Init */ zmd->zone_bitmap_size = dev->zone_nr_blocks >>3 ; - zmd->zone_nr_bitmap_blocks = zmd->zone_bitmap_size >>DMZ_BLOCK_SHIFT ; + zmd->zone_nr_bitmap_blocks = +max_t (sector_t,1 , zmd->zone_bitmap_size >>DMZ_BLOCK_SHIFT ); + zmd->zone_bits_per_mblk =min_t (sector_t, dev->zone_nr_blocks, +DMZ_BLOCK_SIZE_BITS );/* Allocate zone array */ zmd->zones =kcalloc (dev->nr_zones,sizeof (struct dm_zone ),GFP_KERNEL );
@@ -1982,7 +1986,7 @@ int dmz_copy_valid_blocks(struct dmz_metdmz_release_mblock (zmd, to_mblk);dmz_release_mblock (zmd, from_mblk); - chunk_block +=DMZ_BLOCK_SIZE_BITS ; + chunk_block += zmd->zone_bits_per_mblk; } to_zone->weight = from_zone->weight;
@@ -2043,7 +2047,7 @@ int dmz_validate_blocks(struct dmz_metad/* Set bits */ bit = chunk_block &DMZ_BLOCK_MASK_BITS ; - nr_bits =min (nr_blocks,DMZ_BLOCK_SIZE_BITS - bit); + nr_bits =min (nr_blocks, zmd->zone_bits_per_mblk - bit); count =dmz_set_bits ((unsigned long *)mblk->data, bit, nr_bits);if (count) {
@@ -2122,7 +2126,7 @@ int dmz_invalidate_blocks(struct dmz_met/* Clear bits */ bit = chunk_block &DMZ_BLOCK_MASK_BITS ; - nr_bits =min (nr_blocks,DMZ_BLOCK_SIZE_BITS - bit); + nr_bits =min (nr_blocks, zmd->zone_bits_per_mblk - bit); count =dmz_clear_bits ((unsigned long *)mblk->data, bit, nr_bits);
@@ -2182,6 +2186,7 @@ static int dmz_to_next_set_block(struct {struct dmz_mblock *mblk;unsigned int bit, set_bit, nr_bits; +unsigned int zone_bits = zmd->zone_bits_per_mblk;unsigned long *bitmap;int n =0 ;
@@ -2196,15 +2201,15 @@ static int dmz_to_next_set_block(struct/* Get offset */ bitmap = (unsigned long *) mblk->data; bit = chunk_block &DMZ_BLOCK_MASK_BITS ; - nr_bits =min (nr_blocks,DMZ_BLOCK_SIZE_BITS - bit); + nr_bits =min (nr_blocks, zone_bits - bit);if (set) - set_bit =find_next_bit (bitmap,DMZ_BLOCK_SIZE_BITS , bit); + set_bit =find_next_bit (bitmap, zone_bits, bit);else - set_bit =find_next_zero_bit (bitmap,DMZ_BLOCK_SIZE_BITS , bit); + set_bit =find_next_zero_bit (bitmap, zone_bits, bit);dmz_release_mblock (zmd, mblk); n += set_bit - bit; -if (set_bit <DMZ_BLOCK_SIZE_BITS ) +if (set_bit < zone_bits)break ; nr_blocks -= nr_bits;
@@ -2307,7 +2312,7 @@ static void dmz_get_zone_weight(struct d/* Count bits in this block */ bitmap = mblk->data; bit = chunk_block &DMZ_BLOCK_MASK_BITS ; - nr_bits =min (nr_blocks,DMZ_BLOCK_SIZE_BITS - bit); + nr_bits =min (nr_blocks, zmd->zone_bits_per_mblk - bit); n +=dmz_count_bits (bitmap, bit, nr_bits);dmz_release_mblock (zmd, mblk);
Greg Kroah-Hartman
maintainerPATCH 56/173 dm crypt: fix benbi IV constructor crash if used in authenticated mode
In reply to Greg Kroah-HartmanFrom: Milan Broz <[email protected]>
commit 4ea9471fbd1addb25a4d269991dc724e200ca5b5 upstream.
If benbi IV is used in AEAD construction, for example:
cryptsetup luksFormat <device> --cipher twofish-xts-benbi --key-size 512 --integrity=hmac-sha256
the constructor uses wrong skcipher function and crashes:
BUG: kernel NULL pointer dereference, address: 00000014 ... EIP: crypt_iv_benbi_ctr+0x15/0x70 [dm_crypt] Call Trace: ? crypt_subkey_size+0x20/0x20 [dm_crypt] crypt_ctr+0x567/0xfc0 [dm_crypt] dm_table_add_target+0x15f/0x340 [dm_mod]
Fix this by properly using crypt_aead_blocksize() in this case.
--- drivers/md/dm-crypt.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/md/dm-crypt.c +8 -2
@@ -485,8 +485,14 @@ static int crypt_iv_essiv_gen(struct crystatic int crypt_iv_benbi_ctr (struct crypt_config *cc,struct dm_target *ti,const char *opts) { -unsigned bs =crypto_skcipher_blocksize (any_tfm (cc)); -int log =ilog2 (bs); +unsigned bs; +int log; + +if (test_bit (CRYPT_MODE_INTEGRITY_AEAD , &cc->cipher_flags)) + bs =crypto_aead_blocksize (any_tfm_aead (cc)); +else + bs =crypto_skcipher_blocksize (any_tfm (cc)); + log =ilog2 (bs);/* we need to calculate how far we must shift the sector count * to get the cipher block count, we use this shift in _gen */
Greg Kroah-Hartman
maintainerPATCH 52/173 PM: core: Fix handling of devices deleted during system-wide resume
In reply to Greg Kroah-HartmanFrom: Rafael J. Wysocki <[email protected]>
commit 0552e05fdfea191a2cf3a0abd33574b5ef9ca818 upstream.
If a device is deleted by one of its system-wide resume callbacks (for example, because it does not appear to be present or accessible any more) along with its children, the resume of the children may continue leading to use-after-free errors and other issues (potentially).
Namely, if the device's children are resumed asynchronously, their resume may have been scheduled already before the device's callback runs and so the device may be deleted while dpm_wait_for_superior() is being executed for them. The memory taken up by the parent device object may be freed then while dpm_wait() is waiting for the parent's resume callback to complete, which leads to a use-after-free. Moreover, the resume of the children is really not expected to continue after they have been unregistered, so it must be terminated right away in that case.
To address this problem, modify dpm_wait_for_superior() to check if the target device is still there in the system-wide PM list of devices and if so, to increment its parent's reference counter, both under dpm_list_mtx which prevents device_del() running for the child from dropping the parent's reference counter prematurely.
If the device is not present in the system-wide PM list of devices any more, the resume of it cannot continue, so check that again after dpm_wait() returns, which means that the parent's callback has been completed, and pass the result of that check to the caller of dpm_wait_for_superior() to allow it to abort the device's resume if it is not there any more.
--- drivers/base/power/main.c | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-)
drivers/base/power/main.c +37 -5
@@ -269,10 +269,38 @@ static void dpm_wait_for_suppliers(strucdevice_links_read_unlock (idx); } -static void dpm_wait_for_superior (struct device *dev,bool async) +static bool dpm_wait_for_superior (struct device *dev,bool async) { -dpm_wait (dev->parent, async); +struct device *parent; + +/* +* If the device is resumed asynchronously and the parent's callback +* deletes both the device and the parent itself, the parent object may +* be freed while this function is running, so avoid that by reference +* counting the parent once more unless the device has been deleted +* already (in which case return right away). +*/ +mutex_lock (&dpm_list_mtx); + +if (!device_pm_initialized (dev)) { +mutex_unlock (&dpm_list_mtx); +return false; + } + + parent =get_device (dev->parent); + +mutex_unlock (&dpm_list_mtx); + +dpm_wait (parent, async); +put_device (parent); +dpm_wait_for_suppliers (dev, async); + +/* +* If the parent's callback has deleted the device, attempting to resume +* it would be invalid, so avoid doing that then. +*/ +return device_pm_initialized (dev); }static void dpm_wait_for_consumers (struct device *dev,bool async)
@@ -551,7 +579,8 @@ static int device_resume_noirq(struct deif (!dev->power.is_noirq_suspended) goto Out; -dpm_wait_for_superior (dev, async); +if (!dpm_wait_for_superior (dev, async)) + goto Out;if (dev->pm_domain) { info ="noirq power domain " ;
@@ -691,7 +720,8 @@ static int device_resume_early(struct deif (!dev->power.is_late_suspended) goto Out; -dpm_wait_for_superior (dev, async); +if (!dpm_wait_for_superior (dev, async)) + goto Out;if (dev->pm_domain) { info ="early power domain " ;
@@ -823,7 +853,9 @@ static int device_resume(struct device * goto Complete; } -dpm_wait_for_superior (dev, async); +if (!dpm_wait_for_superior (dev, async)) + goto Complete; +dpm_watchdog_set (&wd, dev);device_lock (dev);
Greg Kroah-Hartman
maintainerPATCH 53/173 of: Add OF_DMA_DEFAULT_COHERENT & select it on powerpc
In reply to Greg Kroah-HartmanFrom: Michael Ellerman <[email protected]>
commit dabf6b36b83a18d57e3d4b9d50544ed040d86255 upstream.
There's an OF helper called of_dma_is_coherent(), which checks if a device has a "dma-coherent" property to see if the device is coherent for DMA.
But on some platforms devices are coherent by default, and on some platforms it's not possible to update existing device trees to add the "dma-coherent" property.
So add a Kconfig symbol to allow arch code to tell of_dma_is_coherent() that devices are coherent by default, regardless of the presence of the property.
Select that symbol on powerpc when NOT_COHERENT_CACHE is not set, ie. when the system has a coherent cache.
--- arch/powerpc/Kconfig | 1 + drivers/of/Kconfig | 4 ++++ drivers/of/address.c | 6 +++++- 3 files changed, 10 insertions(+), 1 deletion(-)
arch/powerpc/Kconfig +1 -0
@@ -225,6 +225,7 @@ config PPC select MODULES_USE_ELF_RELA select NO_BOOTMEM select OF + select OF_DMA_DEFAULT_COHERENT if !NOT_COHERENT_CACHE select OF_EARLY_FLATTREE select OF_RESERVED_MEM select OLD_SIGACTION if PPC32
drivers/of/Kconfig +4 -0
@@ -112,4 +112,8 @@ config OF_OVERLAY config OF_NUMA bool +config OF_DMA_DEFAULT_COHERENT + # arches should select this if DMA is coherent by default for OF devices + bool + endif # OF
drivers/of/address.c +5 -1
@@ -894,12 +894,16 @@ EXPORT_SYMBOL_GPL(of_dma_get_range);* @np: device node * * It returns true if "dma-coherent" property was found -* for this device in DT. +* for this device in the DT, or if DMA is coherent by +* default for OF devices on the current platform. */ bool of_dma_is_coherent (struct device_node *np) {struct device_node *node =of_node_get (np); +if (IS_ENABLED (CONFIG_OF_DMA_DEFAULT_COHERENT )) +return true; +while (node) {if (of_property_read_bool (node,"dma-coherent" )) {of_node_put (node);