5.7.5-rc1 review
Subsystems (7)
Greg Kroah-Hartman
maintainerPATCH 152/376 powerpc/spufs: fix copy_to_user while atomic
In reply to Greg Kroah-HartmanFrom: Jeremy Kerr <[email protected]>
[ Upstream commit 88413a6bfbbe2f648df399b62f85c934460b7a4d ]
Currently, we may perform a copy_to_user (through simple_read_from_buffer()) while holding a context's register_lock, while accessing the context save area.
This change uses a temporary buffer for the context save area data, which we then pass to simple_read_from_buffer.
Includes changes from Christoph Hellwig <[email protected]>.
--- arch/powerpc/platforms/cell/spufs/file.c | 113 +++++++++++++++-------- 1 file changed, 75 insertions(+), 38 deletions(-)
arch/powerpc/platforms/cell/spufs/file.c +75 -38
@@ -1978,8 +1978,9 @@ static ssize_t __spufs_mbox_info_read(struct spu_context *ctx,static ssize_t spufs_mbox_info_read (struct file *file,char __user *buf,size_t len,loff_t *pos) { -int ret;struct spu_context *ctx = file->private_data; +u32 stat, data; +int ret;if (!access_ok (buf, len))return -EFAULT ;
@@ -1988,11 +1989,16 @@ static ssize_t spufs_mbox_info_read(struct file *file, char __user *buf,if (ret)return ret;spin_lock (&ctx->csa.register_lock); - ret =__spufs_mbox_info_read (ctx, buf, len, pos); + stat = ctx->csa.prob.mb_stat_R; + data = ctx->csa.prob.pu_mb_R;spin_unlock (&ctx->csa.register_lock);spu_release_saved (ctx); -return ret; +/* EOF if there's no entry in the mbox */ +if (!(stat &0x0000ff )) +return 0 ; + +return simple_read_from_buffer (buf, len, pos, &data,sizeof (data)); }static const struct file_operations spufs_mbox_info_fops = {
@@ -2019,6 +2025,7 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { struct spu_context *ctx = file->private_data; +u32 stat, data;int ret;if (!access_ok (buf, len))
@@ -2028,11 +2035,16 @@ static ssize_t spufs_ibox_info_read(struct file *file, char __user *buf,if (ret)return ret;spin_lock (&ctx->csa.register_lock); - ret =__spufs_ibox_info_read (ctx, buf, len, pos); + stat = ctx->csa.prob.mb_stat_R; + data = ctx->csa.priv2.puint_mb_R;spin_unlock (&ctx->csa.register_lock);spu_release_saved (ctx); -return ret; +/* EOF if there's no entry in the ibox */ +if (!(stat &0xff0000 )) +return 0 ; + +return simple_read_from_buffer (buf, len, pos, &data,sizeof (data)); }static const struct file_operations spufs_ibox_info_fops = {
@@ -2041,6 +2053,11 @@ static const struct file_operations spufs_ibox_info_fops = { .llseek = generic_file_llseek, }; +static size_t spufs_wbox_info_cnt (struct spu_context *ctx) +{ +return (4 - ((ctx->csa.prob.mb_stat_R &0x00ff00 ) >>8 )) *sizeof (u32); +} +static ssize_t __spufs_wbox_info_read (struct spu_context *ctx,char __user *buf,size_t len,loff_t *pos) {
@@ -2049,7 +2066,7 @@ static ssize_t __spufs_wbox_info_read(struct spu_context *ctx,u32 wbox_stat; wbox_stat = ctx->csa.prob.mb_stat_R; - cnt =4 - ((wbox_stat &0x00ff00 ) >>8 ); + cnt =spufs_wbox_info_cnt (ctx);for (i =0 ; i < cnt; i++) { data[i] = ctx->csa.spu_mailbox_data[i]; }
@@ -2062,7 +2079,8 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { struct spu_context *ctx = file->private_data; -int ret; +u32 data[ARRAY_SIZE (ctx->csa.spu_mailbox_data)]; +int ret, count;if (!access_ok (buf, len))return -EFAULT ;
@@ -2071,11 +2089,13 @@ static ssize_t spufs_wbox_info_read(struct file *file, char __user *buf,if (ret)return ret;spin_lock (&ctx->csa.register_lock); - ret =__spufs_wbox_info_read (ctx, buf, len, pos); + count =spufs_wbox_info_cnt (ctx); +memcpy (&data, &ctx->csa.spu_mailbox_data,sizeof (data));spin_unlock (&ctx->csa.register_lock);spu_release_saved (ctx); -return ret; +return simple_read_from_buffer (buf, len, pos, &data, + count *sizeof (u32)); }static const struct file_operations spufs_wbox_info_fops = {
@@ -2084,27 +2104,33 @@ static const struct file_operations spufs_wbox_info_fops = { .llseek = generic_file_llseek, }; -static ssize_t __spufs_dma_info_read (struct spu_context *ctx, -char __user *buf,size_t len,loff_t *pos) +static void spufs_get_dma_info (struct spu_context *ctx, +struct spu_dma_info *info) { -struct spu_dma_info info; -struct mfc_cq_sr *qp, *spuqp;int i; - info.dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW; - info.dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0 ]; - info.dma_info_status = ctx->csa.spu_chnldata_RW[24 ]; - info.dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25 ]; - info.dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27 ]; + info->dma_info_type = ctx->csa.priv2.spu_tag_status_query_RW; + info->dma_info_mask = ctx->csa.lscsa->tag_mask.slot[0 ]; + info->dma_info_status = ctx->csa.spu_chnldata_RW[24 ]; + info->dma_info_stall_and_notify = ctx->csa.spu_chnldata_RW[25 ]; + info->dma_info_atomic_command_status = ctx->csa.spu_chnldata_RW[27 ];for (i =0 ; i <16 ; i++) { - qp = &info.dma_info_command_data[i]; - spuqp = &ctx->csa.priv2.spuq[i]; +struct mfc_cq_sr *qp = &info->dma_info_command_data[i]; +struct mfc_cq_sr *spuqp = &ctx->csa.priv2.spuq[i]; qp->mfc_cq_data0_RW = spuqp->mfc_cq_data0_RW; qp->mfc_cq_data1_RW = spuqp->mfc_cq_data1_RW; qp->mfc_cq_data2_RW = spuqp->mfc_cq_data2_RW; qp->mfc_cq_data3_RW = spuqp->mfc_cq_data3_RW; } +} + +static ssize_t __spufs_dma_info_read (struct spu_context *ctx, +char __user *buf,size_t len,loff_t *pos) +{ +struct spu_dma_info info; + +spufs_get_dma_info (ctx, &info);return simple_read_from_buffer (buf, len, pos, &info,sizeof info);
@@ -2114,6 +2140,7 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { struct spu_context *ctx = file->private_data; +struct spu_dma_info info;int ret;if (!access_ok (buf, len))
@@ -2123,11 +2150,12 @@ static ssize_t spufs_dma_info_read(struct file *file, char __user *buf,if (ret)return ret;spin_lock (&ctx->csa.register_lock); - ret =__spufs_dma_info_read (ctx, buf, len, pos); +spufs_get_dma_info (ctx, &info);spin_unlock (&ctx->csa.register_lock);spu_release_saved (ctx); -return ret; +return simple_read_from_buffer (buf, len, pos, &info, +sizeof (info)); }static const struct file_operations spufs_dma_info_fops = {
@@ -2136,13 +2164,31 @@ static const struct file_operations spufs_dma_info_fops = { .llseek = no_llseek, }; +static void spufs_get_proxydma_info (struct spu_context *ctx, +struct spu_proxydma_info *info) +{ +int i; + + info->proxydma_info_type = ctx->csa.prob.dma_querytype_RW; + info->proxydma_info_mask = ctx->csa.prob.dma_querymask_RW; + info->proxydma_info_status = ctx->csa.prob.dma_tagstatus_R; + +for (i =0 ; i <8 ; i++) { +struct mfc_cq_sr *qp = &info->proxydma_info_command_data[i]; +struct mfc_cq_sr *puqp = &ctx->csa.priv2.puq[i]; + + qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW; + qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW; + qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW; + qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW; + } +} +static ssize_t __spufs_proxydma_info_read (struct spu_context *ctx,char __user *buf,size_t len,loff_t *pos) {struct spu_proxydma_info info; -struct mfc_cq_sr *qp, *puqp;int ret =sizeof info; -int i;if (len < ret)return -EINVAL ;
@@ -2150,18 +2196,7 @@ static ssize_t __spufs_proxydma_info_read(struct spu_context *ctx,if (!access_ok (buf, len))return -EFAULT ; - info.proxydma_info_type = ctx->csa.prob.dma_querytype_RW; - info.proxydma_info_mask = ctx->csa.prob.dma_querymask_RW; - info.proxydma_info_status = ctx->csa.prob.dma_tagstatus_R; -for (i =0 ; i <8 ; i++) { - qp = &info.proxydma_info_command_data[i]; - puqp = &ctx->csa.priv2.puq[i]; - - qp->mfc_cq_data0_RW = puqp->mfc_cq_data0_RW; - qp->mfc_cq_data1_RW = puqp->mfc_cq_data1_RW; - qp->mfc_cq_data2_RW = puqp->mfc_cq_data2_RW; - qp->mfc_cq_data3_RW = puqp->mfc_cq_data3_RW; - } +spufs_get_proxydma_info (ctx, &info);return simple_read_from_buffer (buf, len, pos, &info,sizeof info);
@@ -2171,17 +2206,19 @@ static ssize_t spufs_proxydma_info_read(struct file *file, char __user *buf, size_t len, loff_t *pos) { struct spu_context *ctx = file->private_data; +struct spu_proxydma_info info;int ret; ret =spu_acquire_saved (ctx);if (ret)return ret;spin_lock (&ctx->csa.register_lock); - ret =__spufs_proxydma_info_read (ctx, buf, len, pos); +spufs_get_proxydma_info (ctx, &info);spin_unlock (&ctx->csa.register_lock);spu_release_saved (ctx); -return ret; +return simple_read_from_buffer (buf, len, pos, &info, +sizeof (info)); } static const struct file_operations spufs_proxydma_info_fops = {
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 153/376 ath11k: fix kernel panic by freeing the msdu received with invalid length
In reply to Greg Kroah-HartmanFrom: Tamizh Chelvam <[email protected]>
[ Upstream commit d7d43782d541edb8596d2f4fc7f41b0734948ec5 ]
In certain scenario host receives the packets with invalid length which causes below kernel panic. Free up those msdus to avoid this kernel panic.
2270.028121: <6> task: ffffffc0008306d0 ti: ffffffc0008306d0 task.ti: ffffffc0008306d0 2270.035247: <2> PC is at skb_panic+0x40/0x44 2270.042784: <2> LR is at skb_panic+0x40/0x44 2270.521775: <2> [<ffffffc0004a06e0>] skb_panic+0x40/0x44 2270.524039: <2> [<ffffffc0004a1278>] skb_put+0x54/0x5c 2270.529264: <2> [<ffffffbffcc373a8>] ath11k_dp_process_rx_err+0x320/0x5b0 [ath11k] 2270.533860: <2> [<ffffffbffcc30b68>] ath11k_dp_service_srng+0x80/0x268 [ath11k] 2270.541063: <2> [<ffffffbffcc1d554>] ath11k_hal_rx_reo_ent_buf_paddr_get+0x200/0xb64 [ath11k] 2270.547917: <2> [<ffffffc0004b1f74>] net_rx_action+0xf8/0x274 2270.556247: <2> [<ffffffc000099df4>] __do_softirq+0x128/0x228 2270.561625: <2> [<ffffffc00009a130>] irq_exit+0x84/0xcc 2270.567008: <2> [<ffffffc0000cfb28>] __handle_domain_irq+0x8c/0xb0 2270.571695: <2> [<ffffffc000082484>] gic_handle_irq+0x6c/0xbc
--- drivers/net/wireless/ath/ath11k/dp_rx.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
drivers/net/wireless/ath/ath11k/dp_rx.c +18 -0
@@ -2265,6 +2265,7 @@ static int ath11k_dp_rx_process_msdu(struct ath11k *ar,struct ieee80211_hdr *hdr;struct sk_buff *last_buf;u8 l3_pad_bytes; +u8 *hdr_status;u16 msdu_len;int ret;
@@ -2293,8 +2294,13 @@ static int ath11k_dp_rx_process_msdu(struct ath11k *ar,skb_pull (msdu,HAL_RX_DESC_SIZE ); }else if (!rxcb->is_continuation) {if ((msdu_len +HAL_RX_DESC_SIZE ) >DP_RX_BUFFER_SIZE ) { + hdr_status =ath11k_dp_rx_h_80211_hdr (rx_desc); ret = -EINVAL ;ath11k_warn (ar->ab,"invalid msdu len %u\n" , msdu_len); +ath11k_dbg_dump (ar->ab,ATH11K_DBG_DATA ,NULL ,"" , hdr_status, +sizeof (struct ieee80211_hdr )); +ath11k_dbg_dump (ar->ab,ATH11K_DBG_DATA ,NULL ,"" , rx_desc, +sizeof (struct hal_rx_desc )); goto free_out; }skb_put (msdu,HAL_RX_DESC_SIZE + l3_pad_bytes + msdu_len);
@@ -3389,6 +3395,7 @@ ath11k_dp_process_rx_err_buf(struct ath11k *ar, u32 *ring_desc, int buf_id, boolstruct sk_buff *msdu;struct ath11k_skb_rxcb *rxcb;struct hal_rx_desc *rx_desc; +u8 *hdr_status;u16 msdu_len;spin_lock_bh (&rx_ring->idr_lock);
@@ -3426,6 +3433,17 @@ ath11k_dp_process_rx_err_buf(struct ath11k *ar, u32 *ring_desc, int buf_id, bool rx_desc = (struct hal_rx_desc *)msdu->data; msdu_len =ath11k_dp_rx_h_msdu_start_msdu_len (rx_desc); +if ((msdu_len +HAL_RX_DESC_SIZE ) >DP_RX_BUFFER_SIZE ) { + hdr_status =ath11k_dp_rx_h_80211_hdr (rx_desc); +ath11k_warn (ar->ab,"invalid msdu leng %u" , msdu_len); +ath11k_dbg_dump (ar->ab,ATH11K_DBG_DATA ,NULL ,"" , hdr_status, +sizeof (struct ieee80211_hdr )); +ath11k_dbg_dump (ar->ab,ATH11K_DBG_DATA ,NULL ,"" , rx_desc, +sizeof (struct hal_rx_desc )); +dev_kfree_skb_any (msdu); + goto exit; + } +skb_put (msdu,HAL_RX_DESC_SIZE + msdu_len);if (ath11k_dp_rx_frag_h_mpdu (ar, msdu, ring_desc)) {
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 154/376 libertas_tf: avoid a null dereference in pointer priv
In reply to Greg Kroah-HartmanFrom: Colin Ian King <[email protected]>
[ Upstream commit 049ceac308b0d57c4f06b9fb957cdf95d315cf0b ]
Currently there is a check if priv is null when calling lbtf_remove_card but not in a previous call to if_usb_reset_dev that can also dereference priv. Fix this by also only calling lbtf_remove_card if priv is null.
It is noteable that there don't seem to be any bugs reported that the null pointer dereference has ever occurred, so I'm not sure if the null check is required, but since we're doing a null check anyway it should be done for both function calls.
Addresses-Coverity: ("Dereference before null check")
--- drivers/net/wireless/marvell/libertas_tf/if_usb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/wireless/marvell/libertas_tf/if_usb.c +3 -3
@@ -247,10 +247,10 @@ static void if_usb_disconnect(struct usb_interface *intf)lbtf_deb_enter (LBTF_DEB_MAIN ); -if_usb_reset_device (priv); - -if (priv) +if (priv) { +if_usb_reset_device (priv);lbtf_remove_card (priv); + }/* Unlink and free urb */ if_usb_free (cardp);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 155/376 xfs: clean up the error handling in xfs_swap_extents
In reply to Greg Kroah-HartmanFrom: Darrick J. Wong <[email protected]>
[ Upstream commit 8bc3b5e4b70d28f8edcafc3c9e4de515998eea9e ]
Make sure we release resources properly if we cannot clean out the COW extents in preparation for an extent swap.
--- fs/xfs/xfs_bmap_util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/xfs/xfs_bmap_util.c +1 -1
@@ -1606,7 +1606,7 @@ xfs_swap_extents(if (xfs_inode_has_cow_data (tip)) { error =xfs_reflink_cancel_cow_range (tip,0 ,NULLFILEOFF , true);if (error) -return error; + goto out_unlock; }/*
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 156/376 Crypto/chcr: fix ctr, cbc, xts and rfc3686-ctr failed tests
In reply to Greg Kroah-HartmanFrom: Devulapally Shiva Krishna <[email protected]>
[ Upstream commit 6b363a286cd01961423f5dcd648b265088ec56d0 ]
This solves the following issues observed during self test when CONFIG_CRYPTO_MANAGER_EXTRA_TESTS is enabled.
1. Added fallback for cbc, ctr and rfc3686 if req->nbytes is zero and for xts added a fallback case if req->nbytes is not multiple of 16.
2. In case of cbc-aes, solved wrong iv update. When chcr_cipher_fallback() is called, used req->info pointer instead of reqctx->iv.
3. In cbc-aes decryption there was a wrong result. This occurs when chcr_cipher_fallback() is called from chcr_handle_cipher_resp(). In the fallback function iv(req->info) used is wrongly updated. So use the initial iv for this case.
4)In case of ctr-aes encryption observed wrong result. In adjust_ctr_overflow() there is condition which checks if ((bytes / AES_BLOCK_SIZE) > c), where c is the number of blocks which can be processed without iv overflow, but for the above bytes (req->nbytes < 32 , not a multiple of 16) this condition fails and the 2nd block is corrupted as it requires the rollover iv. So added a '=' condition in this to take care of this.
5)In rfc3686-ctr there was wrong result observed. This occurs when chcr_cipher_fallback() is called from chcr_handle_cipher_resp(). Here also copying initial_iv in init_iv pointer for handling the fallback case correctly.
--- drivers/crypto/chelsio/chcr_algo.c | 42 ++++++++++++++++++---------- drivers/crypto/chelsio/chcr_crypto.h | 1 + 2 files changed, 29 insertions(+), 14 deletions(-)
drivers/crypto/chelsio/chcr_algo.c +28 -14
@@ -1054,8 +1054,8 @@ static unsigned int adjust_ctr_overflow(u8 *iv, u32 bytes)u32 temp =be32_to_cpu (*--b); temp = ~temp; - c = (u64 )temp +1 ;// No of block can processed withou overflow -if ((bytes /AES_BLOCK_SIZE ) > c) + c = (u64 )temp +1 ;// No of block can processed without overflow +if ((bytes /AES_BLOCK_SIZE ) >= c) bytes = c *AES_BLOCK_SIZE ;return bytes; }
@@ -1158,15 +1158,16 @@ static int chcr_final_cipher_iv(struct skcipher_request *req,static int chcr_handle_cipher_resp (struct skcipher_request *req,unsigned char *input,int err) { +struct chcr_skcipher_req_ctx *reqctx =skcipher_request_ctx (req);struct crypto_skcipher *tfm =crypto_skcipher_reqtfm (req); -struct chcr_context *ctx =c_ctx (tfm); -struct uld_ctx *u_ctx =ULD_CTX (c_ctx (tfm)); -struct ablk_ctx *ablkctx =ABLK_CTX (c_ctx (tfm)); -struct sk_buff *skb;struct cpl_fw6_pld *fw6_pld = (struct cpl_fw6_pld *)input; -struct chcr_skcipher_req_ctx *reqctx =skcipher_request_ctx (req); -struct cipher_wr_param wrparam; +struct ablk_ctx *ablkctx =ABLK_CTX (c_ctx (tfm)); +struct uld_ctx *u_ctx =ULD_CTX (c_ctx (tfm));struct chcr_dev *dev =c_ctx (tfm)->dev; +struct chcr_context *ctx =c_ctx (tfm); +struct adapter *adap =padap (ctx->dev); +struct cipher_wr_param wrparam; +struct sk_buff *skb;int bytes;if (err)
@@ -1197,6 +1198,8 @@ static int chcr_handle_cipher_resp(struct skcipher_request *req,if (unlikely (bytes ==0 )) {chcr_cipher_dma_unmap (&ULD_CTX (c_ctx (tfm))->lldi.pdev->dev, req); +memcpy (req->iv, reqctx->init_iv,IV ); +atomic_inc (&adap->chcr_stats.fallback); err = chcr_cipher_fallback(ablkctx->sw_cipher, req->base.flags, req->src,
@@ -1248,20 +1251,28 @@ static int process_cipher(struct skcipher_request *req, struct sk_buff **skb, unsigned short op_type) { +struct chcr_skcipher_req_ctx *reqctx =skcipher_request_ctx (req);struct crypto_skcipher *tfm =crypto_skcipher_reqtfm (req);unsigned int ivsize =crypto_skcipher_ivsize (tfm); -struct chcr_skcipher_req_ctx *reqctx =skcipher_request_ctx (req);struct ablk_ctx *ablkctx =ABLK_CTX (c_ctx (tfm)); +struct adapter *adap =padap (c_ctx (tfm)->dev);struct cipher_wr_param wrparam;int bytes, err = -EINVAL ; +int subtype; reqctx->processed =0 ; reqctx->partial_req =0 ;if (!req->iv) goto error; + subtype =get_cryptoalg_subtype (tfm);if ((ablkctx->enckey_len ==0 ) || (ivsize >AES_BLOCK_SIZE ) || (req->cryptlen ==0 ) || (req->cryptlen %crypto_skcipher_blocksize (tfm))) { +if (req->cryptlen ==0 && subtype !=CRYPTO_ALG_SUB_TYPE_XTS ) + goto fallback; +else if (req->cryptlen %crypto_skcipher_blocksize (tfm) && + subtype ==CRYPTO_ALG_SUB_TYPE_XTS ) + goto fallback;pr_err ("AES: Invalid value of Key Len %d nbytes %d IV Len %d\n" , ablkctx->enckey_len, req->cryptlen, ivsize); goto error;
@@ -1302,12 +1313,10 @@ static int process_cipher(struct skcipher_request *req, }else { bytes = req->cryptlen; } -if (get_cryptoalg_subtype (tfm) == -CRYPTO_ALG_SUB_TYPE_CTR ) { +if (subtype ==CRYPTO_ALG_SUB_TYPE_CTR ) { bytes =adjust_ctr_overflow (req->iv, bytes); } -if (get_cryptoalg_subtype (tfm) == -CRYPTO_ALG_SUB_TYPE_CTR_RFC3686 ) { +if (subtype ==CRYPTO_ALG_SUB_TYPE_CTR_RFC3686 ) {memcpy (reqctx->iv, ablkctx->nonce,CTR_RFC3686_NONCE_SIZE );memcpy (reqctx->iv +CTR_RFC3686_NONCE_SIZE , req->iv,CTR_RFC3686_IV_SIZE );
@@ -1315,20 +1324,25 @@ static int process_cipher(struct skcipher_request *req,/* initialize counter portion of counter block */ *(__be32 *)(reqctx->iv +CTR_RFC3686_NONCE_SIZE +CTR_RFC3686_IV_SIZE ) =cpu_to_be32 (1 ); +memcpy (reqctx->init_iv, reqctx->iv,IV ); }else {memcpy (reqctx->iv, req->iv,IV ); +memcpy (reqctx->init_iv, req->iv,IV ); }if (unlikely (bytes ==0 )) {chcr_cipher_dma_unmap (&ULD_CTX (c_ctx (tfm))->lldi.pdev->dev, req); +fallback:atomic_inc (&adap->chcr_stats.fallback); err =chcr_cipher_fallback (ablkctx->sw_cipher, req->base.flags, req->src, req->dst, req->cryptlen, - reqctx->iv, + subtype == +CRYPTO_ALG_SUB_TYPE_CTR_RFC3686 ? + reqctx->iv : req->iv, op_type); goto error; }
drivers/crypto/chelsio/chcr_crypto.h +1 -0
@@ -302,6 +302,7 @@ struct chcr_skcipher_req_ctx {unsigned int op;u16 imm;u8 iv[CHCR_MAX_CRYPTO_IV_LEN ]; +u8 init_iv[CHCR_MAX_CRYPTO_IV_LEN ];u16 txqidx;u16 rxqidx; };
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 157/376 Crypto/chcr: fix for ccm(aes) failed test
In reply to Greg Kroah-HartmanFrom: Devulapally Shiva Krishna <[email protected]>
[ Upstream commit 10b0c75d7bc19606fa9a62c8ab9180e95c0e0385 ]
The ccm(aes) test fails when req->assoclen > ~240bytes.
The problem is the value assigned to auth_offset is wrong. As auth_offset is unsigned char, it can take max value as 255. So fix it by making it unsigned int.
--- drivers/crypto/chelsio/chcr_algo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/crypto/chelsio/chcr_algo.c +1 -1
@@ -2925,7 +2925,7 @@ static void fill_sec_cpl_for_aead(struct cpl_tx_sec_pdu *sec_cpl,unsigned int mac_mode =CHCR_SCMD_AUTH_MODE_CBCMAC ;unsigned int rx_channel_id = reqctx->rxqidx / ctx->rxq_perchan;unsigned int ccm_xtra; -unsigned char tag_offset =0 , auth_offset =0 ; +unsigned int tag_offset =0 , auth_offset =0 ;unsigned int assoclen;if (get_aead_subtype (tfm) ==CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309 )
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 158/376 dsa: sja1105: dynamically allocate stats structure
In reply to Greg Kroah-HartmanFrom: Arnd Bergmann <[email protected]>
[ Upstream commit ae1804de93f6f1626906567ae7deec8e0111259d ]
The addition of sja1105_port_status_ether structure into the statistics causes the frame size to go over the warning limit:
drivers/net/dsa/sja1105/sja1105_ethtool.c:421:6: error: stack frame size of 1104 bytes in function 'sja1105_get_ethtool_stats' [-Werror,-Wframe-larger-than=]
Use dynamic allocation to avoid this.
--- drivers/net/dsa/sja1105/sja1105_ethtool.c | 144 +++++++++++----------- 1 file changed, 74 insertions(+), 70 deletions(-)
drivers/net/dsa/sja1105/sja1105_ethtool.c +74 -70
@@ -421,92 +421,96 @@ static char sja1105pqrs_extra_port_stats[][ETH_GSTRING_LEN] = {void sja1105_get_ethtool_stats (struct dsa_switch *ds,int port,u64 *data) {struct sja1105_private *priv = ds->priv; -struct sja1105_port_status status; +struct sja1105_port_status *status;int rc, i, k =0 ; -memset (&status,0 ,sizeof (status)); + status =kzalloc (sizeof (*status),GFP_KERNEL ); +if (!status) + goto out; - rc =sja1105_port_status_get (priv, &status, port); + rc =sja1105_port_status_get (priv, status, port);if (rc <0 ) {dev_err (ds->dev,"Failed to read port %d counters: %d\n" , port, rc); -return ; + goto out; }memset (data,0 ,ARRAY_SIZE (sja1105_port_stats) *sizeof (u64)); - data[k++] = status.mac.n_runt; - data[k++] = status.mac.n_soferr; - data[k++] = status.mac.n_alignerr; - data[k++] = status.mac.n_miierr; - data[k++] = status.mac.typeerr; - data[k++] = status.mac.sizeerr; - data[k++] = status.mac.tctimeout; - data[k++] = status.mac.priorerr; - data[k++] = status.mac.nomaster; - data[k++] = status.mac.memov; - data[k++] = status.mac.memerr; - data[k++] = status.mac.invtyp; - data[k++] = status.mac.intcyov; - data[k++] = status.mac.domerr; - data[k++] = status.mac.pcfbagdrop; - data[k++] = status.mac.spcprior; - data[k++] = status.mac.ageprior; - data[k++] = status.mac.portdrop; - data[k++] = status.mac.lendrop; - data[k++] = status.mac.bagdrop; - data[k++] = status.mac.policeerr; - data[k++] = status.mac.drpnona664err; - data[k++] = status.mac.spcerr; - data[k++] = status.mac.agedrp; - data[k++] = status.hl1.n_n664err; - data[k++] = status.hl1.n_vlanerr; - data[k++] = status.hl1.n_unreleased; - data[k++] = status.hl1.n_sizeerr; - data[k++] = status.hl1.n_crcerr; - data[k++] = status.hl1.n_vlnotfound; - data[k++] = status.hl1.n_ctpolerr; - data[k++] = status.hl1.n_polerr; - data[k++] = status.hl1.n_rxfrm; - data[k++] = status.hl1.n_rxbyte; - data[k++] = status.hl1.n_txfrm; - data[k++] = status.hl1.n_txbyte; - data[k++] = status.hl2.n_qfull; - data[k++] = status.hl2.n_part_drop; - data[k++] = status.hl2.n_egr_disabled; - data[k++] = status.hl2.n_not_reach; + data[k++] = status->mac.n_runt; + data[k++] = status->mac.n_soferr; + data[k++] = status->mac.n_alignerr; + data[k++] = status->mac.n_miierr; + data[k++] = status->mac.typeerr; + data[k++] = status->mac.sizeerr; + data[k++] = status->mac.tctimeout; + data[k++] = status->mac.priorerr; + data[k++] = status->mac.nomaster; + data[k++] = status->mac.memov; + data[k++] = status->mac.memerr; + data[k++] = status->mac.invtyp; + data[k++] = status->mac.intcyov; + data[k++] = status->mac.domerr; + data[k++] = status->mac.pcfbagdrop; + data[k++] = status->mac.spcprior; + data[k++] = status->mac.ageprior; + data[k++] = status->mac.portdrop; + data[k++] = status->mac.lendrop; + data[k++] = status->mac.bagdrop; + data[k++] = status->mac.policeerr; + data[k++] = status->mac.drpnona664err; + data[k++] = status->mac.spcerr; + data[k++] = status->mac.agedrp; + data[k++] = status->hl1.n_n664err; + data[k++] = status->hl1.n_vlanerr; + data[k++] = status->hl1.n_unreleased; + data[k++] = status->hl1.n_sizeerr; + data[k++] = status->hl1.n_crcerr; + data[k++] = status->hl1.n_vlnotfound; + data[k++] = status->hl1.n_ctpolerr; + data[k++] = status->hl1.n_polerr; + data[k++] = status->hl1.n_rxfrm; + data[k++] = status->hl1.n_rxbyte; + data[k++] = status->hl1.n_txfrm; + data[k++] = status->hl1.n_txbyte; + data[k++] = status->hl2.n_qfull; + data[k++] = status->hl2.n_part_drop; + data[k++] = status->hl2.n_egr_disabled; + data[k++] = status->hl2.n_not_reach;if (priv->info->device_id ==SJA1105E_DEVICE_ID || priv->info->device_id ==SJA1105T_DEVICE_ID ) -return ; + goto out;;memset (data + k,0 ,ARRAY_SIZE (sja1105pqrs_extra_port_stats) *sizeof (u64));for (i =0 ; i <8 ; i++) { - data[k++] = status.hl2.qlevel_hwm[i]; - data[k++] = status.hl2.qlevel[i]; + data[k++] = status->hl2.qlevel_hwm[i]; + data[k++] = status->hl2.qlevel[i]; } - data[k++] = status.ether.n_drops_nolearn; - data[k++] = status.ether.n_drops_noroute; - data[k++] = status.ether.n_drops_ill_dtag; - data[k++] = status.ether.n_drops_dtag; - data[k++] = status.ether.n_drops_sotag; - data[k++] = status.ether.n_drops_sitag; - data[k++] = status.ether.n_drops_utag; - data[k++] = status.ether.n_tx_bytes_1024_2047; - data[k++] = status.ether.n_tx_bytes_512_1023; - data[k++] = status.ether.n_tx_bytes_256_511; - data[k++] = status.ether.n_tx_bytes_128_255; - data[k++] = status.ether.n_tx_bytes_65_127; - data[k++] = status.ether.n_tx_bytes_64; - data[k++] = status.ether.n_tx_mcast; - data[k++] = status.ether.n_tx_bcast; - data[k++] = status.ether.n_rx_bytes_1024_2047; - data[k++] = status.ether.n_rx_bytes_512_1023; - data[k++] = status.ether.n_rx_bytes_256_511; - data[k++] = status.ether.n_rx_bytes_128_255; - data[k++] = status.ether.n_rx_bytes_65_127; - data[k++] = status.ether.n_rx_bytes_64; - data[k++] = status.ether.n_rx_mcast; - data[k++] = status.ether.n_rx_bcast; + data[k++] = status->ether.n_drops_nolearn; + data[k++] = status->ether.n_drops_noroute; + data[k++] = status->ether.n_drops_ill_dtag; + data[k++] = status->ether.n_drops_dtag; + data[k++] = status->ether.n_drops_sotag; + data[k++] = status->ether.n_drops_sitag; + data[k++] = status->ether.n_drops_utag; + data[k++] = status->ether.n_tx_bytes_1024_2047; + data[k++] = status->ether.n_tx_bytes_512_1023; + data[k++] = status->ether.n_tx_bytes_256_511; + data[k++] = status->ether.n_tx_bytes_128_255; + data[k++] = status->ether.n_tx_bytes_65_127; + data[k++] = status->ether.n_tx_bytes_64; + data[k++] = status->ether.n_tx_mcast; + data[k++] = status->ether.n_tx_bcast; + data[k++] = status->ether.n_rx_bytes_1024_2047; + data[k++] = status->ether.n_rx_bytes_512_1023; + data[k++] = status->ether.n_rx_bytes_256_511; + data[k++] = status->ether.n_rx_bytes_128_255; + data[k++] = status->ether.n_rx_bytes_65_127; + data[k++] = status->ether.n_rx_bytes_64; + data[k++] = status->ether.n_rx_mcast; + data[k++] = status->ether.n_rx_bcast; +out: +kfree (status); } void sja1105_get_strings(struct dsa_switch *ds, int port,
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 159/376 MIPS: Truncate link address into 32bit for 32bit kernel
In reply to Greg Kroah-HartmanFrom: Jiaxun Yang <[email protected]>
[ Upstream commit ff487d41036035376e47972c7c522490b839ab37 ]
LLD failed to link vmlinux with 64bit load address for 32bit ELF while bfd will strip 64bit address into 32bit silently.
To fix LLD build, we should truncate load address provided by platform into 32bit for 32bit kernel.
--- arch/mips/Makefile | 13 ++++++++++++- arch/mips/boot/compressed/Makefile | 2 +- arch/mips/kernel/vmlinux.lds.S | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-)
arch/mips/Makefile +12 -1
@@ -288,12 +288,23 @@ ifdef CONFIG_64BIT endif endif +# When linking a 32-bit executable the LLVM linker cannot cope with a +# 32-bit load address that has been sign-extended to 64 bits. Simply +# remove the upper 32 bits then, as it is safe to do so with other +# linkers. +ifdef CONFIG_64BIT + load-ld = $(load-y) +else + load-ld = $(subst 0xffffffff,0x,$(load-y)) +endif + KBUILD_AFLAGS += $(cflags-y) KBUILD_CFLAGS += $(cflags-y) -KBUILD_CPPFLAGS += -DVMLINUX_LOAD_ADDRESS=$(load-y) +KBUILD_CPPFLAGS += -DVMLINUX_LOAD_ADDRESS=$(load-y) -DLINKER_LOAD_ADDRESS=$(load-ld) KBUILD_CPPFLAGS += -DDATAOFFSET=$(if $(dataoffset-y),$(dataoffset-y),0) bootvars-y = VMLINUX_LOAD_ADDRESS=$(load-y) \ + LINKER_LOAD_ADDRESS=$(load-ld) \ VMLINUX_ENTRY_ADDRESS=$(entry-y) \ PLATFORM="$(platform-y)" \ ITS_INPUTS="$(its-y)"
arch/mips/boot/compressed/Makefile +1 -1
@@ -90,7 +90,7 @@ ifneq ($(zload-y),) VMLINUZ_LOAD_ADDRESS := $(zload-y) else VMLINUZ_LOAD_ADDRESS = $(shell $(obj)/calc_vmlinuz_load_addr \ - $(obj)/vmlinux.bin $(VMLINUX_LOAD_ADDRESS)) + $(obj)/vmlinux.bin $(LINKER_LOAD_ADDRESS)) endif UIMAGE_LOADADDR = $(VMLINUZ_LOAD_ADDRESS)
arch/mips/kernel/vmlinux.lds.S +1 -1
@@ -55,7 +55,7 @@ SECTIONS /* . = 0xa800000000300000; */ . = 0xffffffff80300000; #endif - . = VMLINUX_LOAD_ADDRESS; + . = LINKER_LOAD_ADDRESS; /* read-only */ _text = .; /* Text and read-only data */ .text : {
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 160/376 mips: cm: Fix an invalid error code of INTVN_*_ERR
In reply to Greg Kroah-HartmanFrom: Serge Semin <[email protected]>
[ Upstream commit 8a0efb8b101665a843205eab3d67ab09cb2d9a8d ]
Commit 3885c2b463f6 ("MIPS: CM: Add support for reporting CM cache errors") adds cm2_causes[] array with map of error type ID and pointers to the short description string. There is a mistake in the table, since according to MIPS32 manual CM2_ERROR_TYPE = {17,18} correspond to INTVN_WR_ERR and INTVN_RD_ERR, while the table claims they have {0x17,0x18} codes. This is obviously hex-dec copy-paste bug. Moreover codes {0x18 - 0x1a} indicate L2 ECC errors.
--- arch/mips/kernel/mips-cm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/mips/kernel/mips-cm.c +3 -3
@@ -119,9 +119,9 @@ static char *cm2_causes[32] = {"COH_RD_ERR" ,"MMIO_WR_ERR" ,"MMIO_RD_ERR" ,"0x07" ,"0x08" ,"0x09" ,"0x0a" ,"0x0b" ,"0x0c" ,"0x0d" ,"0x0e" ,"0x0f" , -"0x10" ,"0x11" ,"0x12" ,"0x13" , -"0x14" ,"0x15" ,"0x16" ,"INTVN_WR_ERR" , -"INTVN_RD_ERR" ,"0x19" ,"0x1a" ,"0x1b" , +"0x10" ,"INTVN_WR_ERR" ,"INTVN_RD_ERR" ,"0x13" , +"0x14" ,"0x15" ,"0x16" ,"0x17" , +"0x18" ,"0x19" ,"0x1a" ,"0x1b" ,"0x1c" ,"0x1d" ,"0x1e" ,"0x1f" };
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 161/376 kgdb: Fix spurious true from in_dbg_master()
In reply to Greg Kroah-HartmanFrom: Daniel Thompson <[email protected]>
[ Upstream commit 3fec4aecb311995189217e64d725cfe84a568de3 ]
Currently there is a small window where a badly timed migration could cause in_dbg_master() to spuriously return true. Specifically if we migrate to a new core after reading the processor id and the previous core takes a breakpoint then we will evaluate true if we read kgdb_active before we get the IPI to bring us to halt.
Fix this by checking irqs_disabled() first. Interrupts are always disabled when we are executing the kgdb trap so this is an acceptable prerequisite. This also allows us to replace raw_smp_processor_id() with smp_processor_id() since the short circuit logic will prevent warnings from PREEMPT_DEBUG.
--- include/linux/kgdb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/kgdb.h +1 -1
@@ -323,7 +323,7 @@ extern void gdbstub_exit(int status);extern int kgdb_single_step;extern atomic_t kgdb_active;#define in_dbg_master () \ - (raw_smp_processor_id() == atomic_read(&kgdb_active)) + (irqs_disabled() && (smp_processor_id() == atomic_read(&kgdb_active)))extern bool dbg_is_early;extern void __init dbg_late_init (void );extern void kgdb_panic (const char *msg);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 162/376 xfs: reset buffer write failure state on successful completion
In reply to Greg Kroah-HartmanFrom: Brian Foster <[email protected]>
[ Upstream commit b6983e80b03bd4fd42de71993b3ac7403edac758 ]
The buffer write failure flag is intended to control the internal write retry that XFS has historically implemented to help mitigate the severity of transient I/O errors. The flag is set when a buffer is resubmitted from the I/O completion path due to a previous failure. It is checked on subsequent I/O completions to skip the internal retry and fall through to the higher level configurable error handling mechanism. The flag is cleared in the synchronous and delwri submission paths and also checked in various places to log write failure messages.
There are a couple minor problems with the current usage of this flag. One is that we issue an internal retry after every submission from xfsaild due to how delwri submission clears the flag. This results in double the expected or configured number of write attempts when under sustained failures. Another more subtle issue is that the flag is never cleared on successful I/O completion. This can cause xfs_wait_buftarg() to suggest that dirty buffers are being thrown away due to the existence of the flag, when the reality is that the flag might still be set because the write succeeded on the retry.
Clear the write failure flag on successful I/O completion to address both of these problems. This means that the internal retry attempt occurs once since the last time a buffer write failed and that various other contexts only see the flag set when the immediately previous write attempt has failed.
--- fs/xfs/xfs_buf.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
fs/xfs/xfs_buf.c +5 -3
@@ -1197,8 +1197,10 @@ xfs_buf_ioend( bp->b_ops->verify_read (bp); } -if (!bp->b_error) +if (!bp->b_error) { + bp->b_flags &= ~XBF_WRITE_FAIL ; bp->b_flags |=XBF_DONE ; + }if (bp->b_iodone) (*(bp->b_iodone))(bp);
@@ -1258,7 +1260,7 @@ xfs_bwrite( bp->b_flags |=XBF_WRITE ; bp->b_flags &= ~(XBF_ASYNC |XBF_READ | _XBF_DELWRI_Q | -XBF_WRITE_FAIL |XBF_DONE ); +XBF_DONE ); error =xfs_buf_submit (bp);if (error)
@@ -1983,7 +1985,7 @@ xfs_buf_delwri_submit_buffers(* synchronously. Otherwise, drop the buffer from the delwri * queue and submit async. */ - bp->b_flags &= ~(_XBF_DELWRI_Q |XBF_WRITE_FAIL ); + bp->b_flags &= ~_XBF_DELWRI_Q; bp->b_flags |=XBF_WRITE ;if (wait_list) { bp->b_flags &= ~XBF_ASYNC ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 163/376 xfs: fix duplicate verification from xfs_qm_dqflush()
In reply to Greg Kroah-HartmanFrom: Brian Foster <[email protected]>
[ Upstream commit 629dcb38dc351947ed6a26a997d4b587f3bd5c7e ]
The pre-flush dquot verification in xfs_qm_dqflush() duplicates the read verifier by checking the dquot in the on-disk buffer. Instead, verify the in-core variant before it is flushed to the buffer.
--- fs/xfs/xfs_dquot.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
fs/xfs/xfs_dquot.c +4 -5
@@ -1116,13 +1116,12 @@ xfs_qm_dqflush( dqb = bp->b_addr + dqp->q_bufoffset; ddqp = &dqb->dd_diskdq; -/* -* A simple sanity check in case we got a corrupted dquot. -*/ - fa =xfs_dqblk_verify (mp, dqb,be32_to_cpu (ddqp->d_id),0 ); +/* sanity check the in-core structure before we flush */ + fa =xfs_dquot_verify (mp, &dqp->q_core,be32_to_cpu (dqp->q_core.d_id), +0 );if (fa) {xfs_alert (mp,"corrupt dquot ID 0x%x in memory at %pS" , -be32_to_cpu (ddqp->d_id), fa); +be32_to_cpu (dqp->q_core.d_id), fa);xfs_buf_relse (bp);xfs_dqfunlock (dqp);xfs_force_shutdown (mp,SHUTDOWN_CORRUPT_INCORE );
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 164/376 platform/x86: intel-vbtn: Use acpi_evaluate_integer()
In reply to Greg Kroah-HartmanFrom: Hans de Goede <[email protected]>
[ Upstream commit 18937875a231d831c309716d6d8fc358f8381881 ]
Use acpi_evaluate_integer() instead of open-coding it.
This is a preparation patch for adding a intel_vbtn_has_switches() helper function.
--- drivers/platform/x86/intel-vbtn.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-)
drivers/platform/x86/intel-vbtn.c +6 -13
@@ -119,28 +119,21 @@ static void detect_tablet_mode(struct platform_device *device)const char *chassis_type =dmi_get_system_info (DMI_CHASSIS_TYPE );struct intel_vbtn_priv *priv =dev_get_drvdata (&device->dev);acpi_handle handle =ACPI_HANDLE (&device->dev); -struct acpi_buffer vgbs_output = {ACPI_ALLOCATE_BUFFER ,NULL }; -union acpi_object *obj; +unsigned long long vgbs;acpi_status status;int m;if (!(chassis_type &&strcmp (chassis_type,"31" ) ==0 )) - goto out; +return ; - status =acpi_evaluate_object (handle,"VGBS" ,NULL , &vgbs_output); + status =acpi_evaluate_integer (handle,"VGBS" ,NULL , &vgbs);if (ACPI_FAILURE (status)) - goto out; - - obj = vgbs_output.pointer; -if (!(obj && obj->type ==ACPI_TYPE_INTEGER )) - goto out; +return ; - m = !(obj->integer.value &TABLET_MODE_FLAG ); + m = !(vgbs &TABLET_MODE_FLAG );input_report_switch (priv->input_dev,SW_TABLET_MODE , m); - m = (obj->integer.value &DOCK_MODE_FLAG ) ?1 :0 ; + m = (vgbs &DOCK_MODE_FLAG ) ?1 :0 ;input_report_switch (priv->input_dev,SW_DOCK , m); -out: -kfree (vgbs_output.pointer); }static int intel_vbtn_probe (struct platform_device *device)
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 165/376 platform/x86: intel-vbtn: Split keymap into buttons and switches parts
In reply to Greg Kroah-HartmanFrom: Hans de Goede <[email protected]>
[ Upstream commit f6ba524970c4b73b234bf41ecd6628f5803b1559 ]
Split the sparse keymap into 2 separate keymaps, a buttons and a switches keymap and combine the 2 to a single map again in intel_vbtn_input_setup().
This is a preparation patch for not telling userspace that we have switches when we do not have them (and for doing the same for the buttons).
--- drivers/platform/x86/intel-vbtn.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-)
drivers/platform/x86/intel-vbtn.c +25 -3
@@ -40,14 +40,20 @@ static const struct key_entry intel_vbtn_keymap[] = { { KE_IGNORE, 0xC7, { KEY_VOLUMEDOWN } }, /* volume-down key release */ { KE_KEY, 0xC8, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key press */ { KE_KEY, 0xC9, { KEY_ROTATE_LOCK_TOGGLE } }, /* rotate-lock key release */ +}; + +static const struct key_entry intel_vbtn_switchmap[] = { {KE_SW ,0xCA , { .sw = {SW_DOCK ,1 } } },/* Docked */ {KE_SW ,0xCB , { .sw = {SW_DOCK ,0 } } },/* Undocked */ {KE_SW ,0xCC , { .sw = {SW_TABLET_MODE ,1 } } },/* Tablet */ {KE_SW ,0xCD , { .sw = {SW_TABLET_MODE ,0 } } },/* Laptop */ - { KE_END }, }; +#define KEYMAP_LEN \ + (ARRAY_SIZE(intel_vbtn_keymap) + ARRAY_SIZE(intel_vbtn_switchmap) + 1) +struct intel_vbtn_priv { +struct key_entry keymap[KEYMAP_LEN ];struct input_dev *input_dev;bool wakeup_mode; };
@@ -55,13 +61,29 @@ struct intel_vbtn_priv {static int intel_vbtn_input_setup (struct platform_device *device) {struct intel_vbtn_priv *priv =dev_get_drvdata (&device->dev); -int ret; +int ret, keymap_len =0 ; + +if (true) { +memcpy (&priv->keymap[keymap_len], intel_vbtn_keymap, +ARRAY_SIZE (intel_vbtn_keymap) * +sizeof (struct key_entry )); + keymap_len +=ARRAY_SIZE (intel_vbtn_keymap); + } + +if (true) { +memcpy (&priv->keymap[keymap_len], intel_vbtn_switchmap, +ARRAY_SIZE (intel_vbtn_switchmap) * +sizeof (struct key_entry )); + keymap_len +=ARRAY_SIZE (intel_vbtn_switchmap); + } + + priv->keymap[keymap_len].type =KE_END ; priv->input_dev =devm_input_allocate_device (&device->dev);if (!priv->input_dev)return -ENOMEM ; - ret =sparse_keymap_setup (priv->input_dev, intel_vbtn_keymap,NULL ); + ret =sparse_keymap_setup (priv->input_dev, priv->keymap,NULL );if (ret)return ret;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 166/376 platform/x86: intel-vbtn: Do not advertise switches to userspace if they are not there
In reply to Greg Kroah-HartmanFrom: Hans de Goede <[email protected]>
[ Upstream commit 990fbb48067bf8cfa34b7d1e6e1674eaaef2f450 ]
Commit de9647efeaa9 ("platform/x86: intel-vbtn: Only activate tablet mode switch on 2-in-1's") added a DMI chassis-type check to avoid accidentally reporting SW_TABLET_MODE = 1 to userspace on laptops (specifically on the Dell XPS 9360), to avoid e.g. userspace ignoring touchpad events because userspace thought the device was in tablet-mode.
But if we are not getting the initial status of the switch because the device does not have a tablet mode, then we really should not advertise the presence of a tablet-mode switch to userspace at all, as userspace may use the mere presence of this switch for certain heuristics.
--- drivers/platform/x86/intel-vbtn.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-)
drivers/platform/x86/intel-vbtn.c +19 -6
@@ -55,6 +55,7 @@ static const struct key_entry intel_vbtn_switchmap[] = {struct intel_vbtn_priv {struct key_entry keymap[KEYMAP_LEN ];struct input_dev *input_dev; +bool has_switches;bool wakeup_mode; };
@@ -70,7 +71,7 @@ static int intel_vbtn_input_setup(struct platform_device *device) keymap_len +=ARRAY_SIZE (intel_vbtn_keymap); } -if (true) { +if (priv->has_switches) {memcpy (&priv->keymap[keymap_len], intel_vbtn_switchmap,ARRAY_SIZE (intel_vbtn_switchmap) *sizeof (struct key_entry ));
@@ -138,16 +139,12 @@ out_unknown:static void detect_tablet_mode (struct platform_device *device) { -const char *chassis_type =dmi_get_system_info (DMI_CHASSIS_TYPE );struct intel_vbtn_priv *priv =dev_get_drvdata (&device->dev);acpi_handle handle =ACPI_HANDLE (&device->dev);unsigned long long vgbs;acpi_status status;int m; -if (!(chassis_type &&strcmp (chassis_type,"31" ) ==0 )) -return ; - status =acpi_evaluate_integer (handle,"VGBS" ,NULL , &vgbs);if (ACPI_FAILURE (status))return ;
@@ -158,6 +155,19 @@ static void detect_tablet_mode(struct platform_device *device)input_report_switch (priv->input_dev,SW_DOCK , m); } +static bool intel_vbtn_has_switches (acpi_handle handle) +{ +const char *chassis_type =dmi_get_system_info (DMI_CHASSIS_TYPE ); +unsigned long long vgbs; +acpi_status status; + +if (!(chassis_type &&strcmp (chassis_type,"31" ) ==0 )) +return false; + + status =acpi_evaluate_integer (handle,"VGBS" ,NULL , &vgbs); +return ACPI_SUCCESS (status); +} +static int intel_vbtn_probe (struct platform_device *device) {acpi_handle handle =ACPI_HANDLE (&device->dev);
@@ -176,13 +186,16 @@ static int intel_vbtn_probe(struct platform_device *device)return -ENOMEM ;dev_set_drvdata (&device->dev, priv); + priv->has_switches =intel_vbtn_has_switches (handle); + err =intel_vbtn_input_setup (device);if (err) {pr_err ("Failed to setup Intel Virtual Button\n" );return err; } -detect_tablet_mode (device); +if (priv->has_switches) +detect_tablet_mode (device); status = acpi_install_notify_handler(handle, ACPI_DEVICE_NOTIFY,
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 167/376 platform/x86: intel-vbtn: Also handle tablet-mode switch on "Detachable" and "Portable" chassis-types
In reply to Greg Kroah-HartmanFrom: Hans de Goede <[email protected]>
[ Upstream commit 1fac39fd0316b19c3e57a182524332332d1643ce ]
Commit de9647efeaa9 ("platform/x86: intel-vbtn: Only activate tablet mode switch on 2-in-1's") added a DMI chassis-type check to avoid accidentally reporting SW_TABLET_MODE = 1 to userspace on laptops.
Some devices with a detachable keyboard and using the intel-vbnt (INT33D6) interface to report if they are in tablet mode (keyboard detached) or not, report 32 / "Detachable" as chassis-type, e.g. the HP Pavilion X2 series.
Other devices with a detachable keyboard and using the intel-vbnt (INT33D6) interface to report SW_TABLET_MODE, report 8 / "Portable" as chassis-type. The Dell Venue 11 Pro 7130 is an example of this.
Extend the DMI chassis-type check to also accept Portables and Detachables so that the intel-vbtn driver will report SW_TABLET_MODE on these devices.
Note the chassis-type check was originally added to avoid a false-positive tablet-mode report on the Dell XPS 9360 laptop. To the best of my knowledge that laptop is using a chassis-type of 9 / "Laptop", so after this commit we still ignore the tablet-switch for that chassis-type.
--- drivers/platform/x86/intel-vbtn.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
drivers/platform/x86/intel-vbtn.c +11 -1
@@ -158,12 +158,22 @@ static void detect_tablet_mode(struct platform_device *device)static bool intel_vbtn_has_switches (acpi_handle handle) {const char *chassis_type =dmi_get_system_info (DMI_CHASSIS_TYPE ); +unsigned long chassis_type_int;unsigned long long vgbs;acpi_status status; -if (!(chassis_type &&strcmp (chassis_type,"31" ) ==0 )) +if (kstrtoul (chassis_type,10 , &chassis_type_int))return false; +switch (chassis_type_int) { +case 8 :/* Portable */ +case 31 :/* Convertible */ +case 32 :/* Detachable */ +break ; +default : +return false; + } + status =acpi_evaluate_integer (handle,"VGBS" ,NULL , &vgbs);return ACPI_SUCCESS (status); }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 168/376 iwlwifi: avoid debug max amsdu config overwriting itself
In reply to Greg Kroah-HartmanFrom: Mordechay Goodstein <[email protected]>
[ Upstream commit a65a5824298b06049dbaceb8a9bd19709dc9507c ]
If we set amsdu_len one after another the second one overwrites the orig_amsdu_len so allow only moving from debug to non debug state.
Also the TLC update check was wrong: it was checking that also the orig is smaller then the new updated size, which is not the case in debug amsdu mode.
--- drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c | 11 +++++++---- drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c | 15 ++++++++------- 2 files changed, 15 insertions(+), 11 deletions(-)
drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c +7 -4
@@ -5,10 +5,9 @@* * GPL LICENSE SUMMARY * -* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH -* Copyright(c) 2018 - 2019 Intel Corporation +* Copyright(c) 2012 - 2014, 2018 - 2020 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as
@@ -28,10 +27,9 @@* * BSD LICENSE * -* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH * Copyright(c) 2016 - 2017 Intel Deutschland GmbH -* Copyright(c) 2018 - 2019 Intel Corporation +* Copyright(c) 2012 - 2014, 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without
@@ -481,6 +479,11 @@ static ssize_t iwl_dbgfs_amsdu_len_write(struct ieee80211_sta *sta,if (kstrtou16 (buf,0 , &amsdu_len))return -EINVAL ; +/* only change from debug set <-> debug unset */ +if ((amsdu_len && mvmsta->orig_amsdu_len) || + (!!amsdu_len && mvmsta->orig_amsdu_len)) +return -EBUSY ; +if (amsdu_len) { mvmsta->orig_amsdu_len = sta->max_amsdu_len; sta->max_amsdu_len = amsdu_len;
drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c +8 -7
@@ -369,14 +369,15 @@ void iwl_mvm_tlc_update_notif(struct iwl_mvm *mvm,u16 size =le32_to_cpu (notif->amsdu_size);int i; -/* -* In debug sta->max_amsdu_len < size -* so also check with orig_amsdu_len which holds the original -* data before debugfs changed the value -*/ -if (WARN_ON (sta->max_amsdu_len < size && - mvmsta->orig_amsdu_len < size)) +if (sta->max_amsdu_len < size) { +/* +* In debug sta->max_amsdu_len < size +* so also check with orig_amsdu_len which holds the +* original data before debugfs changed the value +*/ +WARN_ON (mvmsta->orig_amsdu_len < size); goto out; + } mvmsta->amsdu_enabled =le32_to_cpu (notif->amsdu_enabled); mvmsta->max_amsdu_len = size;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 169/376 nvme: refine the Qemu Identify CNS quirk
In reply to Greg Kroah-HartmanFrom: Christoph Hellwig <[email protected]>
[ Upstream commit b9a5c3d4c34d8bd9fd75f7f28d18a57cb68da237 ]
Add a helper to check if we can use Identify CNS values > 1, and refine the Qemu quirk to not apply to reported versions larger than 1.1, as the Qemu implementation had been fixed by then.
--- drivers/nvme/host/core.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-)
drivers/nvme/host/core.c +14 -2
@@ -1027,6 +1027,19 @@ void nvme_stop_keep_alive(struct nvme_ctrl *ctrl) }EXPORT_SYMBOL_GPL (nvme_stop_keep_alive); +/* +* In NVMe 1.0 the CNS field was just a binary controller or namespace +* flag, thus sending any new CNS opcodes has a big chance of not working. +* Qemu unfortunately had that bug after reporting a 1.1 version compliance +* (but not for any later version). +*/ +static bool nvme_ctrl_limited_cns (struct nvme_ctrl *ctrl) +{ +if (ctrl->quirks &NVME_QUIRK_IDENTIFY_CNS ) +return ctrl->vs <NVME_VS (1 ,2 ,0 ); +return ctrl->vs <NVME_VS (1 ,1 ,0 ); +} +static int nvme_identify_ctrl (struct nvme_ctrl *dev,struct nvme_id_ctrl **id) {struct nvme_command c = { };
@@ -3815,8 +3828,7 @@ static void nvme_scan_work(struct work_struct *work)mutex_lock (&ctrl->scan_lock); nn =le32_to_cpu (id->nn); -if (ctrl->vs >=NVME_VS (1 ,1 ,0 ) && - !(ctrl->quirks &NVME_QUIRK_IDENTIFY_CNS )) { +if (!nvme_ctrl_limited_cns (ctrl)) {if (!nvme_scan_ns_list (ctrl, nn)) goto out_free_id; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 170/376 nvme-fc: avoid gcc-10 zero-length-bounds warning
In reply to Greg Kroah-HartmanFrom: Arnd Bergmann <[email protected]>
[ Upstream commit 3add1d93d9919b6de94aa47900d4904adffbc976 ]
When CONFIG_ARCH_NO_SG_CHAIN is set, op->sgl[0] cannot be dereferenced, as gcc-10 now points out:
drivers/nvme/host/fc.c: In function 'nvme_fc_init_request':drivers/nvme/host/fc.c:1774:29: warning: array subscript 0 is outside the bounds of an interior zero-length array 'struct scatterlist[0]' [-Wzero-length-bounds]
1774 | op->op.fcp_req.first_sgl = &op->sgl[0];
| ^~~~~~~~~~~drivers/nvme/host/fc.c:98:21: note: while referencing 'sgl'
98 | struct scatterlist sgl[NVME_INLINE_SG_CNT];
| ^~~
I don't know if this is a legitimate warning or a false-positive. If this is just a false alarm, the warning is easily suppressed by interpreting the array as a pointer.
--- drivers/nvme/host/fc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/nvme/host/fc.c +1 -1
@@ -1771,7 +1771,7 @@ nvme_fc_init_request(struct blk_mq_tag_set *set, struct request *rq, res =__nvme_fc_init_request (ctrl, queue, &op->op, rq, queue->rqcnt++);if (res)return res; - op->op.fcp_req.first_sgl = &op->sgl[0 ]; + op->op.fcp_req.first_sgl = op->sgl; op->op.fcp_req.private = &op->priv[0 ];nvme_req (rq)->ctrl = &ctrl->ctrl;return res;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 171/376 nvme-pci: align io queue count with allocted nvme_queue in nvme_probe
In reply to Greg Kroah-HartmanFrom: Weiping Zhang <[email protected]>
[ Upstream commit 2a5bcfdd41d68559567cec3c124a75e093506cc1 ]
Since commit 147b27e4bd08 ("nvme-pci: allocate device queues storage space at probe"), nvme_alloc_queue does not alloc the nvme queues itself anymore.
If the write/poll_queues module parameters are changed at runtime to values larger than the number of allocated queues in nvme_probe, nvme_alloc_queue will access unallocated memory.
Add a new nr_allocated_queues member to struct nvme_dev to record how many queues were alloctated in nvme_probe to avoid using more than the allocated queues after a reset following a change to the write/poll_queues module parameters.
Also add nr_write_queues and nr_poll_queues members to allow refreshing the number of write and poll queues based on a change to the module parameters when resetting the controller.
--- drivers/nvme/host/pci.c | 57 ++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 24 deletions(-)
drivers/nvme/host/pci.c +33 -24
@@ -128,6 +128,9 @@ struct nvme_dev {dma_addr_t host_mem_descs_dma;struct nvme_host_mem_buf_desc *host_mem_descs;void **host_mem_desc_bufs; +unsigned int nr_allocated_queues; +unsigned int nr_write_queues; +unsigned int nr_poll_queues; };static int io_queue_depth_set (const char *val,const struct kernel_param *kp)
@@ -209,25 +212,14 @@ struct nvme_iod {struct scatterlist *sg; }; -static unsigned int max_io_queues (void ) +static inline unsigned int nvme_dbbuf_size (struct nvme_dev *dev) { -return num_possible_cpus () + write_queues + poll_queues; -} - -static unsigned int max_queue_count (void ) -{ -/* IO queues + admin queue */ -return 1 +max_io_queues (); -} - -static inline unsigned int nvme_dbbuf_size (u32 stride) -{ -return (max_queue_count () *8 * stride); +return dev->nr_allocated_queues *8 * dev->db_stride; }static int nvme_dbbuf_dma_alloc (struct nvme_dev *dev) { -unsigned int mem_size =nvme_dbbuf_size (dev->db_stride); +unsigned int mem_size =nvme_dbbuf_size (dev);if (dev->dbbuf_dbs)return 0 ;
@@ -252,7 +244,7 @@ static int nvme_dbbuf_dma_alloc(struct nvme_dev *dev)static void nvme_dbbuf_dma_free (struct nvme_dev *dev) { -unsigned int mem_size =nvme_dbbuf_size (dev->db_stride); +unsigned int mem_size =nvme_dbbuf_size (dev);if (dev->dbbuf_dbs) { dma_free_coherent(dev->dev, mem_size,
@@ -2003,7 +1995,7 @@ static int nvme_setup_host_mem(struct nvme_dev *dev)static void nvme_calc_irq_sets (struct irq_affinity *affd,unsigned int nrirqs) {struct nvme_dev *dev = affd->priv; -unsigned int nr_read_queues; +unsigned int nr_read_queues, nr_write_queues = dev->nr_write_queues;/* * If there is no interupt available for queues, ensure that
@@ -2019,12 +2011,12 @@ static void nvme_calc_irq_sets(struct irq_affinity *affd, unsigned int nrirqs)if (!nrirqs) { nrirqs =1 ; nr_read_queues =0 ; - }else if (nrirqs ==1 || !write_queues) { + }else if (nrirqs ==1 || !nr_write_queues) { nr_read_queues =0 ; - }else if (write_queues >= nrirqs) { + }else if (nr_write_queues >= nrirqs) { nr_read_queues =1 ; }else { - nr_read_queues = nrirqs - write_queues; + nr_read_queues = nrirqs - nr_write_queues; } dev->io_queues[HCTX_TYPE_DEFAULT ] = nrirqs - nr_read_queues;
@@ -2048,7 +2040,7 @@ static int nvme_setup_irqs(struct nvme_dev *dev, unsigned int nr_io_queues)* Poll queues don't need interrupts, but we need at least one IO * queue left over for non-polled IO. */ - this_p_queues = poll_queues; + this_p_queues = dev->nr_poll_queues;if (this_p_queues >= nr_io_queues) { this_p_queues = nr_io_queues -1 ; irq_queues =1 ;
@@ -2078,14 +2070,25 @@ static void nvme_disable_io_queues(struct nvme_dev *dev)__nvme_disable_io_queues (dev, nvme_admin_delete_cq); } +static unsigned int nvme_max_io_queues (struct nvme_dev *dev) +{ +return num_possible_cpus () + dev->nr_write_queues + dev->nr_poll_queues; +} +static int nvme_setup_io_queues (struct nvme_dev *dev) {struct nvme_queue *adminq = &dev->queues[0 ];struct pci_dev *pdev =to_pci_dev (dev->dev); -int result, nr_io_queues; +unsigned int nr_io_queues;unsigned long size; +int result; - nr_io_queues =max_io_queues (); +/* +* Sample the module parameters once at reset time so that we have +* stable values to work with. +*/ + dev->nr_write_queues = write_queues; + dev->nr_poll_queues = poll_queues;/* * If tags are shared with admin queue (Apple bug), then
@@ -2093,6 +2096,9 @@ static int nvme_setup_io_queues(struct nvme_dev *dev)*/ if (dev->ctrl.quirks &NVME_QUIRK_SHARED_TAGS ) nr_io_queues =1 ; +else + nr_io_queues =min (nvme_max_io_queues (dev), + dev->nr_allocated_queues -1 ); result =nvme_set_queue_count (&dev->ctrl, &nr_io_queues);if (result <0 )
@@ -2767,8 +2773,11 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)if (!dev)return -ENOMEM ; - dev->queues =kcalloc_node (max_queue_count (),sizeof (struct nvme_queue ), -GFP_KERNEL , node); + dev->nr_write_queues = write_queues; + dev->nr_poll_queues = poll_queues; + dev->nr_allocated_queues =nvme_max_io_queues (dev) +1 ; + dev->queues =kcalloc_node (dev->nr_allocated_queues, +sizeof (struct nvme_queue ),GFP_KERNEL , node);if (!dev->queues) goto free;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 172/376 nvme-tcp: use bh_lock in data_ready
In reply to Greg Kroah-HartmanFrom: Sagi Grimberg <[email protected]>
[ Upstream commit 386e5e6e1aa90b479fcf0467935922df8524393d ]
data_ready may be invoked from send context or from softirq, so need bh locking for that.
--- drivers/nvme/host/tcp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/nvme/host/tcp.c +2 -2
@@ -794,11 +794,11 @@ static void nvme_tcp_data_ready(struct sock *sk) {struct nvme_tcp_queue *queue; -read_lock (&sk->sk_callback_lock); +read_lock_bh (&sk->sk_callback_lock); queue = sk->sk_user_data;if (likely (queue && queue->rd_enabled))queue_work_on (queue->io_cpu, nvme_tcp_wq, &queue->io_work); -read_unlock (&sk->sk_callback_lock); +read_unlock_bh (&sk->sk_callback_lock); }static void nvme_tcp_write_space (struct sock *sk)
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 173/376 ath10k: Skip handling del_server during driver exit
In reply to Greg Kroah-HartmanFrom: Rakesh Pillai <[email protected]>
[ Upstream commit 7c6d67b136ceb0aebc7a3153b300e925ed915daf ]
The qmi infrastructure sends the client a del_server event when the client releases its qmi handle. This is not the msg indicating the actual qmi server exiting. In such cases the del_server msg should not be processed, since the wifi firmware does not reset its qmi state.
Hence skip the processing of del_server event when the driver is unloading.
Tested HW: WCN3990
Tested FW: WLAN.HL.3.1-01040-QCAHLSWMTPLZ-1
--- drivers/net/wireless/ath/ath10k/qmi.c | 13 ++++++++++++- drivers/net/wireless/ath/ath10k/qmi.h | 6 ++++++ 2 files changed, 18 insertions(+), 1 deletion(-)
drivers/net/wireless/ath/ath10k/qmi.c +12 -1
@@ -961,7 +961,16 @@ static void ath10k_qmi_del_server(struct qmi_handle *qmi_hdl, container_of(qmi_hdl, struct ath10k_qmi, qmi_hdl); qmi->fw_ready = false; -ath10k_qmi_driver_event_post (qmi,ATH10K_QMI_EVENT_SERVER_EXIT ,NULL ); + +/* +* The del_server event is to be processed only if coming from +* the qmi server. The qmi infrastructure sends del_server, when +* any client releases the qmi handle. In this case do not process +* this del_server event. +*/ +if (qmi->state ==ATH10K_QMI_STATE_INIT_DONE ) +ath10k_qmi_driver_event_post (qmi,ATH10K_QMI_EVENT_SERVER_EXIT , +NULL ); }static struct qmi_ops ath10k_qmi_ops = {
@@ -1091,6 +1100,7 @@ int ath10k_qmi_init(struct ath10k *ar, u32 msa_size)if (ret) goto err_qmi_lookup; + qmi->state =ATH10K_QMI_STATE_INIT_DONE ;return 0 ; err_qmi_lookup:
@@ -1109,6 +1119,7 @@ int ath10k_qmi_deinit(struct ath10k *ar)struct ath10k_snoc *ar_snoc =ath10k_snoc_priv (ar);struct ath10k_qmi *qmi = ar_snoc->qmi; + qmi->state =ATH10K_QMI_STATE_DEINIT ;qmi_handle_release (&qmi->qmi_hdl);cancel_work_sync (&qmi->event_work);destroy_workqueue (qmi->event_wq);
drivers/net/wireless/ath/ath10k/qmi.h +6 -0
@@ -83,6 +83,11 @@ struct ath10k_qmi_driver_event {void *data; }; +enum ath10k_qmi_state { +ATH10K_QMI_STATE_INIT_DONE , +ATH10K_QMI_STATE_DEINIT , +}; +struct ath10k_qmi {struct ath10k *ar;struct qmi_handle qmi_hdl;
@@ -105,6 +110,7 @@ struct ath10k_qmi {char fw_build_timestamp[MAX_TIMESTAMP_LEN +1 ];struct ath10k_qmi_cal_data cal_data[MAX_NUM_CAL_V01 ];bool msa_fixed_perm; +enum ath10k_qmi_state state; }; int ath10k_qmi_wlan_enable(struct ath10k *ar,
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 174/376 ath10k: Remove msdu from idr when management pkt send fails
In reply to Greg Kroah-HartmanFrom: Rakesh Pillai <[email protected]>
[ Upstream commit c730c477176ad4af86d9aae4d360a7ad840b073a ]
Currently when the sending of any management pkt via wmi command fails, the packet is being unmapped freed in the error handling. But the idr entry added, which is used to track these packet is not getting removed.
Hence, during unload, in wmi cleanup, all the entries in IDR are removed and the corresponding buffer is attempted to be freed. This can cause a situation where one packet is attempted to be freed twice.
Fix this error by rmeoving the msdu from the idr
list when the sending of a management packet over
wmi fails.
Tested HW: WCN3990
Tested FW: WLAN.HL.3.1-01040-QCAHLSWMTPLZ-1
--- drivers/net/wireless/ath/ath10k/mac.c | 3 +++ drivers/net/wireless/ath/ath10k/wmi-ops.h | 10 ++++++++++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 15 +++++++++++++++ 3 files changed, 28 insertions(+)
drivers/net/wireless/ath/ath10k/mac.c +3 -0
@@ -3921,6 +3921,9 @@ void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work)if (ret) {ath10k_warn (ar,"failed to transmit management frame by ref via WMI: %d\n" , ret); +/* remove this msdu from idr tracking */ +ath10k_wmi_cleanup_mgmt_tx_send (ar, skb); +dma_unmap_single (ar->dev, paddr, skb->len,DMA_TO_DEVICE );ieee80211_free_txskb (ar->hw, skb);
drivers/net/wireless/ath/ath10k/wmi-ops.h +10 -0
@@ -133,6 +133,7 @@ struct wmi_ops {struct sk_buff *(*gen_mgmt_tx_send)(struct ath10k *ar,struct sk_buff *skb,dma_addr_t paddr); +int (*cleanup_mgmt_tx_send)(struct ath10k *ar,struct sk_buff *msdu);struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar,u64 module_enable,u32 log_level);struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar,u32 filter);
@@ -441,6 +442,15 @@ ath10k_wmi_get_txbf_conf_scheme(struct ath10k *ar)return ar->wmi.ops->get_txbf_conf_scheme (ar); } +static inline int +ath10k_wmi_cleanup_mgmt_tx_send (struct ath10k *ar,struct sk_buff *msdu) +{ +if (!ar->wmi.ops->cleanup_mgmt_tx_send) +return -EOPNOTSUPP ; + +return ar->wmi.ops->cleanup_mgmt_tx_send (ar, msdu); +} +static inline int ath10k_wmi_mgmt_tx_send (struct ath10k *ar,struct sk_buff *msdu,dma_addr_t paddr)
drivers/net/wireless/ath/ath10k/wmi-tlv.c +15 -0
@@ -2897,6 +2897,18 @@ ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar, u32 stats_mask)return skb; } +static int +ath10k_wmi_tlv_op_cleanup_mgmt_tx_send (struct ath10k *ar, +struct sk_buff *msdu) +{ +struct ath10k_skb_cb *cb =ATH10K_SKB_CB (msdu); +struct ath10k_wmi *wmi = &ar->wmi; + +idr_remove (&wmi->mgmt_pending_tx, cb->msdu_id); + +return 0 ; +} +static int ath10k_wmi_mgmt_tx_alloc_msdu_id (struct ath10k *ar,struct sk_buff *skb,dma_addr_t paddr)
@@ -2971,6 +2983,8 @@ ath10k_wmi_tlv_op_gen_mgmt_tx_send(struct ath10k *ar, struct sk_buff *msdu,if (desc_id <0 ) goto err_free_skb; + cb->msdu_id = desc_id; + ptr = (void *)skb->data; tlv = ptr; tlv->tag =__cpu_to_le16 (WMI_TLV_TAG_STRUCT_MGMT_TX_CMD );
@@ -4419,6 +4433,7 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,/* .gen_mgmt_tx = not implemented; HTT is used */ .gen_mgmt_tx_send = ath10k_wmi_tlv_op_gen_mgmt_tx_send, + .cleanup_mgmt_tx_send = ath10k_wmi_tlv_op_cleanup_mgmt_tx_send, .gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg, .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable, .gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable,
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 175/376 wcn36xx: Fix error handling path in wcn36xx_probe()
In reply to Greg Kroah-HartmanFrom: Christophe JAILLET <[email protected]>
[ Upstream commit a86308fc534edeceaf64670c691e17485436a4f4 ]
In case of error, 'qcom_wcnss_open_channel()' must be undone by a call to 'rpmsg_destroy_ept()', as already done in the remove function.
--- drivers/net/wireless/ath/wcn36xx/main.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/wireless/ath/wcn36xx/main.c +4 -2
@@ -1339,7 +1339,7 @@ static int wcn36xx_probe(struct platform_device *pdev)if (addr && ret !=ETH_ALEN ) {wcn36xx_err ("invalid local-mac-address\n" ); ret = -EINVAL ; - goto out_wq; + goto out_destroy_ept; }else if (addr) {wcn36xx_info ("mac address: %pM\n" , addr);SET_IEEE80211_PERM_ADDR (wcn->hw, addr);
@@ -1347,7 +1347,7 @@ static int wcn36xx_probe(struct platform_device *pdev) ret =wcn36xx_platform_get_resources (wcn, pdev);if (ret) - goto out_wq; + goto out_destroy_ept;wcn36xx_init_ieee80211 (wcn); ret =ieee80211_register_hw (wcn->hw);
@@ -1359,6 +1359,8 @@ static int wcn36xx_probe(struct platform_device *pdev) out_unmap:iounmap (wcn->ccu_base);iounmap (wcn->dxe_base); +out_destroy_ept: +rpmsg_destroy_ept (wcn->smd_channel); out_wq:ieee80211_free_hw (hw); out_err:
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 176/376 net: qed*: Reduce RX and TX default ring count when running inside kdump kernel
In reply to Greg Kroah-HartmanFrom: Bhupesh Sharma <[email protected]>
[ Upstream commit 73e030977f7884dbe1be0018bab517e8d02760f8 ]
Normally kdump kernel(s) run under severe memory constraint with the basic idea being to save the crashdump vmcore reliably when the primary kernel panics/hangs.
Currently the qed* ethernet driver ends up consuming a lot of memory in the kdump kernel, leading to kdump kernel panic when one tries to save the vmcore via ssh/nfs (thus utilizing the services of the underlying qed* network interfaces).
An example OOM message log seen in the kdump kernel can be seen here [1], with crashkernel size reservation of 512M.
Using tools like memstrack (see [2]), we can track the modules taking up the bulk of memory in the kdump kernel and organize the memory usage output as per 'highest allocator first'. An example log for the OOM case indicates that the qed* modules end up allocating approximately 216M memory, which is a large part of the total crashkernel size:
dracut-pre-pivot[676]: ======== Report format module_summary: ======== dracut-pre-pivot[676]: Module qed using 149.6MB (2394 pages), peak allocation 149.6MB (2394 pages) dracut-pre-pivot[676]: Module qede using 65.3MB (1045 pages), peak allocation 65.3MB (1045 pages)
This patch reduces the default RX and TX ring count from 1024 to 64 when running inside kdump kernel, which leads to a significant memory saving.
An example log with the patch applied shows the reduced memory
allocation in the kdump kernel:
dracut-pre-pivot[674]: ======== Report format module_summary: ======== dracut-pre-pivot[674]: Module qed using 141.8MB (2268 pages), peak allocation 141.8MB (2268 pages) <..snip..>
[dracut-pre-pivot[674]: Module qede using 4.8MB (76 pages), peak allocation 4.9MB (78 pages)
Tested crashdump vmcore save via ssh/nfs protocol using underlying qed* network interface after applying this patch.
[1] OOM log:
------------
kworker/0:6: page allocation failure: order:6, mode:0x60c0c0(GFP_KERNEL|__GFP_COMP|__GFP_ZERO), nodemask=(null) kworker/0:6 cpuset=/ mems_allowed=0
CPU: 0 PID: 145 Comm: kworker/0:6 Not tainted 4.18.0-109.el8.aarch64 #1 Hardware name: To be filled by O.E.M. Saber/Saber, BIOS 0ACKL025 01/18/2019 Workqueue: events work_for_cpu_fn Call trace: dump_backtrace+0x0/0x188 show_stack+0x24/0x30 dump_stack+0x90/0xb4 warn_alloc+0xf4/0x178 __alloc_pages_nodemask+0xcac/0xd58 alloc_pages_current+0x8c/0xf8 kmalloc_order_trace+0x38/0x108 qed_iov_alloc+0x40/0x248 [qed] qed_resc_alloc+0x224/0x518 [qed] qed_slowpath_start+0x254/0x928 [qed] __qede_probe+0xf8/0x5e0 [qede] qede_probe+0x68/0xd8 [qede] local_pci_probe+0x44/0xa8 work_for_cpu_fn+0x20/0x30 process_one_work+0x1ac/0x3e8 worker_thread+0x44/0x448 kthread+0x130/0x138 ret_from_fork+0x10/0x18 Cannot start slowpath qede: probe of 0000:05:00.1 failed with error -12
[2]. Memstrack tool: https://github.com/ryncsn/memstrack
--- drivers/net/ethernet/qlogic/qede/qede.h | 2 ++ drivers/net/ethernet/qlogic/qede/qede_main.c | 11 +++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-)
drivers/net/ethernet/qlogic/qede/qede.h +2 -0
@@ -574,12 +574,14 @@ int qede_add_tc_flower_fltr(struct qede_dev *edev, __be16 proto,#define RX_RING_SIZE ((u16)BIT(RX_RING_SIZE_POW))#define NUM_RX_BDS_MAX (RX_RING_SIZE - 1)#define NUM_RX_BDS_MIN 128 +#define NUM_RX_BDS_KDUMP_MIN 63#define NUM_RX_BDS_DEF ((u16)BIT(10) - 1)#define TX_RING_SIZE_POW 13#define TX_RING_SIZE ((u16)BIT(TX_RING_SIZE_POW))#define NUM_TX_BDS_MAX (TX_RING_SIZE - 1)#define NUM_TX_BDS_MIN 128 +#define NUM_TX_BDS_KDUMP_MIN 63#define NUM_TX_BDS_DEF NUM_TX_BDS_MAX#define QEDE_MIN_PKT_LEN 64
drivers/net/ethernet/qlogic/qede/qede_main.c +9 -2
@@ -29,6 +29,7 @@* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ +#include <linux/crash_dump.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/version.h>
@@ -707,8 +708,14 @@ static struct qede_dev *qede_alloc_etherdev(struct qed_dev *cdev, edev->dp_module = dp_module; edev->dp_level = dp_level; edev->ops = qed_ops; - edev->q_num_rx_buffers =NUM_RX_BDS_DEF ; - edev->q_num_tx_buffers =NUM_TX_BDS_DEF ; + +if (is_kdump_kernel ()) { + edev->q_num_rx_buffers =NUM_RX_BDS_KDUMP_MIN ; + edev->q_num_tx_buffers =NUM_TX_BDS_KDUMP_MIN ; + }else { + edev->q_num_rx_buffers =NUM_RX_BDS_DEF ; + edev->q_num_tx_buffers =NUM_TX_BDS_DEF ; + }DP_INFO (edev,"Allocated netdev with %d tx queues and %d rx queues\n" , info->num_queues, info->num_queues);
Signature · 9 lines
2.25.1 _______________________________________________ kexec mailing list [email protected] http://lists.infradead.org/mailman/listinfo/kexec
Greg Kroah-Hartman
maintainerPATCH 177/376 drm/mcde: dsi: Fix return value check in mcde_dsi_bind()
In reply to Greg Kroah-HartmanFrom: Wei Yongjun <[email protected]>
[ Upstream commit 761e9f4f80a21a4b845097027030bef863001636 ]
The of_drm_find_bridge() function returns NULL on error, it doesn't return error pointers so this check doesn't work.
--- drivers/gpu/drm/mcde/mcde_dsi.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/gpu/drm/mcde/mcde_dsi.c +3 -4
@@ -1073,10 +1073,9 @@ static int mcde_dsi_bind(struct device *dev, struct device *master, panel =NULL ; bridge =of_drm_find_bridge (child); -if (IS_ERR (bridge)) { -dev_err (dev,"failed to find bridge (%ld)\n" , -PTR_ERR (bridge)); -return PTR_ERR (bridge); +if (!bridge) { +dev_err (dev,"failed to find bridge\n" ); +return -EINVAL ; } } }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 178/376 mt76: mt7663: fix mt7615_mac_cca_stats_reset routine
In reply to Greg Kroah-HartmanFrom: Lorenzo Bianconi <[email protected]>
[ Upstream commit 886a862d3677ac0d3b57d19ffcf5b2d48b9c5267 ]
Fix PHYMUX_5 register definition for mt7663 inmt7615_mac_cca_stats_reset routine
--- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 8 +++++++- drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7615/mac.c +7 -1
@@ -1574,8 +1574,14 @@ void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy) {struct mt7615_dev *dev = phy->dev;bool ext_phy = phy != &dev->phy; -u32 reg =MT_WF_PHY_R0_PHYMUX_5 (ext_phy); +u32 reg; +if (is_mt7663 (&dev->mt76)) + reg =MT7663_WF_PHY_R0_PHYMUX_5 ; +else + reg =MT_WF_PHY_R0_PHYMUX_5 (ext_phy); + +/* reset PD and MDRDY counters */ mt76_clear (dev, reg,GENMASK (22 ,20 ));mt76_set (dev, reg,BIT (22 ) |BIT (20 )); }
drivers/net/wireless/mediatek/mt76/mt7615/regs.h +1 -0
@@ -151,6 +151,7 @@ enum mt7615_reg_base {#define MT_WF_PHY_WF2_RFCTRL0_LPBCN_EN BIT(9)#define MT_WF_PHY_R0_PHYMUX_5 (_phy) MT_WF_PHY(0x0614 + ((_phy) << 9)) +#define MT7663_WF_PHY_R0_PHYMUX_5 MT_WF_PHY(0x0414)#define MT_WF_PHY_R0_PHYCTRL_STS0 (_phy) MT_WF_PHY(0x020c + ((_phy) << 9))#define MT_WF_PHYCTRL_STAT_PD_OFDM GENMASK(31, 16)
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 179/376 mt76: mt7615: do not always reset the dfs state setting the channel
In reply to Greg Kroah-HartmanFrom: Lorenzo Bianconi <[email protected]>
[ Upstream commit fdb786cce0ef3615dcbb30d8baf06a1d4cb7a344 ]
mac80211/hostapd runs mt7615_set_channel with the same channel parameters sending multiple rdd commands overwriting the previous ones. This behaviour is causing tpt issues on dfs channels.
Fix the issue checking new channel freq/width with the running one.
--- .../net/wireless/mediatek/mt76/mt7615/main.c | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7615/main.c +20 -1
@@ -218,6 +218,25 @@ static void mt7615_remove_interface(struct ieee80211_hw *hw,spin_unlock_bh (&dev->sta_poll_lock); } +static void mt7615_init_dfs_state (struct mt7615_phy *phy) +{ +struct mt76_phy *mphy = phy->mt76; +struct ieee80211_hw *hw = mphy->hw; +struct cfg80211_chan_def *chandef = &hw->conf.chandef; + +if (hw->conf.flags &IEEE80211_CONF_OFFCHANNEL ) +return ; + +if (!(chandef->chan->flags &IEEE80211_CHAN_RADAR )) +return ; + +if (mphy->chandef.chan->center_freq == chandef->chan->center_freq && + mphy->chandef.width == chandef->width) +return ; + + phy->dfs_state =-1 ; +} +static int mt7615_set_channel (struct mt7615_phy *phy) {struct mt7615_dev *dev = phy->dev;
@@ -229,7 +248,7 @@ static int mt7615_set_channel(struct mt7615_phy *phy)mutex_lock (&dev->mt76.mutex);set_bit (MT76_RESET , &phy->mt76->state); - phy->dfs_state =-1 ; +mt7615_init_dfs_state (phy);mt76_set_channel (phy->mt76); ret =mt7615_mcu_set_chan_info (phy,MCU_EXT_CMD_CHANNEL_SWITCH );
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 180/376 mt76: mt7622: fix DMA unmap length
In reply to Greg Kroah-HartmanFrom: Lorenzo Bianconi <[email protected]>
[ Upstream commit c0f8055b3986f9c9f990268b578173259769ba1c ]
Fix DMA unmap length estimation in mt7615_txp_skb_unmap_hw for mt7622 chipset
--- drivers/net/wireless/mediatek/mt76/mt7615/mac.c | 6 +++--- drivers/net/wireless/mediatek/mt76/mt7615/mac.h | 1 + 2 files changed, 4 insertions(+), 3 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7615/mac.c +3 -3
@@ -675,7 +675,7 @@ mt7615_txp_skb_unmap_hw(struct mt76_dev *dev, struct mt7615_hw_txp *txp) len =le16_to_cpu (ptr->len0); last = len &MT_TXD_LEN_MSDU_LAST ; - len &= ~MT_TXD_LEN_MSDU_LAST ; + len &=MT_TXD_LEN_MASK ;dma_unmap_single (dev->dev,le32_to_cpu (ptr->buf0), len,DMA_TO_DEVICE );if (last)
@@ -683,7 +683,7 @@ mt7615_txp_skb_unmap_hw(struct mt76_dev *dev, struct mt7615_hw_txp *txp) len =le16_to_cpu (ptr->len1); last = len &MT_TXD_LEN_MSDU_LAST ; - len &= ~MT_TXD_LEN_MSDU_LAST ; + len &=MT_TXD_LEN_MASK ;dma_unmap_single (dev->dev,le32_to_cpu (ptr->buf1), len,DMA_TO_DEVICE );if (last)
@@ -1107,8 +1107,8 @@ mt7615_write_hw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info, txp->msdu_id[0 ] =cpu_to_le16 (id |MT_MSDU_ID_VALID );for (i =0 ; i < nbuf; i++) { +u16 len = tx_info->buf[i +1 ].len &MT_TXD_LEN_MASK ;u32 addr = tx_info->buf[i +1 ].addr; -u16 len = tx_info->buf[i +1 ].len;if (i == nbuf -1 ) len |= MT_TXD_LEN_MSDU_LAST |
drivers/net/wireless/mediatek/mt76/mt7615/mac.h +1 -0
@@ -252,6 +252,7 @@ enum tx_phy_bandwidth {#define MT_MSDU_ID_VALID BIT(15) +#define MT_TXD_LEN_MASK GENMASK(11, 0)#define MT_TXD_LEN_MSDU_LAST BIT(14)#define MT_TXD_LEN_AMSDU_LAST BIT(15)
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 181/376 mt76: mt7663: fix DMA unmap length
In reply to Greg Kroah-HartmanFrom: Lorenzo Bianconi <[email protected]>
[ Upstream commit 89829c9e65ab680f7e5a1658cb74bc6316ab036e ]
Fix DMA unmap length for mt7663e devices in mt7615_txp_skb_unmap_hw
--- .../net/wireless/mediatek/mt76/mt7615/mac.c | 20 +++++++++++++------ .../net/wireless/mediatek/mt76/mt7615/mac.h | 2 ++ 2 files changed, 16 insertions(+), 6 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7615/mac.c +14 -6
@@ -666,15 +666,18 @@ mt7615_txp_skb_unmap_fw(struct mt76_dev *dev, struct mt7615_fw_txp *txp)static void mt7615_txp_skb_unmap_hw (struct mt76_dev *dev,struct mt7615_hw_txp *txp) { +u32 last_mask;int i; + last_mask =is_mt7663 (dev) ?MT_TXD_LEN_LAST :MT_TXD_LEN_MSDU_LAST ; +for (i =0 ; i <ARRAY_SIZE (txp->ptr); i++) {struct mt7615_txp_ptr *ptr = &txp->ptr[i];bool last;u16 len; len =le16_to_cpu (ptr->len0); - last = len &MT_TXD_LEN_MSDU_LAST ; + last = len & last_mask; len &=MT_TXD_LEN_MASK ;dma_unmap_single (dev->dev,le32_to_cpu (ptr->buf0), len,DMA_TO_DEVICE );
@@ -682,7 +685,7 @@ mt7615_txp_skb_unmap_hw(struct mt76_dev *dev, struct mt7615_hw_txp *txp)break ; len =le16_to_cpu (ptr->len1); - last = len &MT_TXD_LEN_MSDU_LAST ; + last = len & last_mask; len &=MT_TXD_LEN_MASK ;dma_unmap_single (dev->dev,le32_to_cpu (ptr->buf1), len,DMA_TO_DEVICE );
@@ -1098,21 +1101,26 @@ mt7615_write_hw_txp(struct mt7615_dev *dev, struct mt76_tx_info *tx_info, {struct mt7615_hw_txp *txp = txp_ptr;struct mt7615_txp_ptr *ptr = &txp->ptr[0 ]; -int nbuf = tx_info->nbuf -1 ; -int i; +int i, nbuf = tx_info->nbuf -1 ; +u32 last_mask; tx_info->buf[0 ].len =MT_TXD_SIZE +sizeof (*txp); tx_info->nbuf =1 ; txp->msdu_id[0 ] =cpu_to_le16 (id |MT_MSDU_ID_VALID ); +if (is_mt7663 (&dev->mt76)) + last_mask =MT_TXD_LEN_LAST ; +else + last_mask =MT_TXD_LEN_AMSDU_LAST | +MT_TXD_LEN_MSDU_LAST ; +for (i =0 ; i < nbuf; i++) {u16 len = tx_info->buf[i +1 ].len &MT_TXD_LEN_MASK ;u32 addr = tx_info->buf[i +1 ].addr;if (i == nbuf -1 ) - len |=MT_TXD_LEN_MSDU_LAST | -MT_TXD_LEN_AMSDU_LAST ; + len |= last_mask;if (i &1 ) { ptr->buf1 =cpu_to_le32 (addr);
drivers/net/wireless/mediatek/mt76/mt7615/mac.h +2 -0
@@ -255,6 +255,8 @@ enum tx_phy_bandwidth {#define MT_TXD_LEN_MASK GENMASK(11, 0)#define MT_TXD_LEN_MSDU_LAST BIT(14)#define MT_TXD_LEN_AMSDU_LAST BIT(15) +/* mt7663 */ +#define MT_TXD_LEN_LAST BIT(15)struct mt7615_txp_ptr {__le32 buf0;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 182/376 mt76: mt7615: fix mt7615_firmware_own for mt7663e
In reply to Greg Kroah-HartmanFrom: Lorenzo Bianconi <[email protected]>
[ Upstream commit becdf0d5d7a46f5ed1f12405ffae4b04764fe27c ]
Check the firmware-own configuration has been applied polling MT_CONN_HIF_ON_LPCTL register
--- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +2 -3
@@ -1550,9 +1550,8 @@ static int mt7615_firmware_own(struct mt7615_dev *dev)mt76_wr (dev, addr,MT_CFG_LPCR_HOST_FW_OWN ); -if (is_mt7622 (&dev->mt76) && - !mt76_poll_msec (dev,MT_CFG_LPCR_HOST , -MT_CFG_LPCR_HOST_FW_OWN , +if (!is_mt7615 (&dev->mt76) && + !mt76_poll_msec (dev, addr,MT_CFG_LPCR_HOST_FW_OWN ,MT_CFG_LPCR_HOST_FW_OWN ,3000 )) {dev_err (dev->mt76.dev,"Timeout for firmware own\n" );return -EIO ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 183/376 mt76: mt7615: fix mt7615_driver_own routine
In reply to Greg Kroah-HartmanFrom: Lorenzo Bianconi <[email protected]>
[ Upstream commit 338061619185133f56ac17365deb1e75eaecc604 ]
Introduce MT_PCIE_DOORBELL_PUSH register to fix mt7615_driver_own routine for mt7663e
--- drivers/net/wireless/mediatek/mt76/mt7615/mcu.c | 6 +++++- drivers/net/wireless/mediatek/mt76/mt7615/regs.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-)
drivers/net/wireless/mediatek/mt76/mt7615/mcu.c +5 -1
@@ -1526,16 +1526,20 @@ static void mt7622_trigger_hif_int(struct mt7615_dev *dev, bool en)static int mt7615_driver_own (struct mt7615_dev *dev) { +struct mt76_dev *mdev = &dev->mt76;u32 addr; - addr =is_mt7663 (&dev->mt76) ?MT_CONN_HIF_ON_LPCTL :MT_CFG_LPCR_HOST ; + addr =is_mt7663 (mdev) ?MT_PCIE_DOORBELL_PUSH :MT_CFG_LPCR_HOST ;mt76_wr (dev, addr,MT_CFG_LPCR_HOST_DRV_OWN );mt7622_trigger_hif_int (dev, true); + + addr =is_mt7663 (mdev) ?MT_CONN_HIF_ON_LPCTL :MT_CFG_LPCR_HOST ;if (!mt76_poll_msec (dev, addr,MT_CFG_LPCR_HOST_FW_OWN ,0 ,3000 )) {dev_err (dev->mt76.dev,"Timeout for driver own\n" );return -EIO ; } +mt7622_trigger_hif_int (dev, false);return 0 ;
drivers/net/wireless/mediatek/mt76/mt7615/regs.h +1 -0
@@ -65,6 +65,7 @@ enum mt7615_reg_base {#define MT_HIF2_BASE 0xf0000#define MT_HIF2 (ofs) (MT_HIF2_BASE + (ofs))#define MT_PCIE_IRQ_ENABLE MT_HIF2(0x188) +#define MT_PCIE_DOORBELL_PUSH MT_HIF2(0x1484)#define MT_CFG_LPCR_HOST MT_HIF(0x1f0)#define MT_CFG_LPCR_HOST_FW_OWN BIT(0)
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 184/376 mt76: avoid rx reorder buffer overflow
In reply to Greg Kroah-HartmanFrom: Ryder Lee <[email protected]>
[ Upstream commit 7c4f744d6703757be959f521a7a441bf34745d99 ]
Enlarge slot to support 11ax 256 BA (256 MPDUs in an AMPDU)
--- drivers/net/wireless/mediatek/mt76/agg-rx.c | 8 ++++---- drivers/net/wireless/mediatek/mt76/mt76.h | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-)
drivers/net/wireless/mediatek/mt76/agg-rx.c +4 -4
@@ -152,8 +152,8 @@ void mt76_rx_aggr_reorder(struct sk_buff *skb, struct sk_buff_head *frames)struct ieee80211_sta *sta;struct mt76_rx_tid *tid;bool sn_less; -u16 seqno, head, size; -u8 ackp, idx; +u16 seqno, head, size, idx; +u8 ackp;__skb_queue_tail (frames, skb);
@@ -239,7 +239,7 @@ out: }int mt76_rx_aggr_start (struct mt76_dev *dev,struct mt76_wcid *wcid,u8 tidno, -u16 ssn,u8 size) +u16 ssn,u16 size) {struct mt76_rx_tid *tid;
@@ -264,7 +264,7 @@ EXPORT_SYMBOL_GPL(mt76_rx_aggr_start);static void mt76_rx_aggr_shutdown (struct mt76_dev *dev,struct mt76_rx_tid *tid) { -u8 size = tid->size; +u16 size = tid->size;int i;spin_lock_bh (&tid->lock);
drivers/net/wireless/mediatek/mt76/mt76.h +3 -3
@@ -241,8 +241,8 @@ struct mt76_rx_tid {struct delayed_work reorder_work;u16 head; -u8 size; -u8 nframes; +u16 size; +u16 nframes;u8 num;
@@ -788,7 +788,7 @@ int mt76_get_survey(struct ieee80211_hw *hw, int idx,void mt76_set_stream_caps (struct mt76_dev *dev,bool vht);int mt76_rx_aggr_start (struct mt76_dev *dev,struct mt76_wcid *wcid,u8 tid, -u16 ssn,u8 size); +u16 ssn,u16 size);void mt76_rx_aggr_stop (struct mt76_dev *dev,struct mt76_wcid *wcid,u8 tid); void mt76_wcid_key_setup(struct mt76_dev *dev, struct mt76_wcid *wcid,
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 185/376 selftests/bpf: Install generated test progs
In reply to Greg Kroah-HartmanFrom: Yauheni Kaliuta <[email protected]>
[ Upstream commit 309b81f0fdc4209d998bc63f0da52c2e96340d4e ]
Before commit 74b5a5968fe8 ("selftests/bpf: Replace test_progs and test_maps w/ general rule") selftests/bpf used generic install target from selftests/lib.mk to install generated bpf test progs by mentioning them in TEST_GEN_FILES variable.
Take that functionality back.
--- tools/testing/selftests/bpf/Makefile | 1 + 1 file changed, 1 insertion(+)
tools/testing/selftests/bpf/Makefile +1 -0
@@ -264,6 +264,7 @@ TRUNNER_BPF_OBJS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.o, $$(TRUNNER_BPF_SRCS) TRUNNER_BPF_SKELS := $$(patsubst %.c,$$(TRUNNER_OUTPUT)/%.skel.h, \ $$(filter-out $(SKEL_BLACKLIST), \ $$(TRUNNER_BPF_SRCS))) +TEST_GEN_FILES += $$(TRUNNER_BPF_OBJS) # Evaluate rules now with extra TRUNNER_XXX variables above already defined $$(eval $$(call DEFINE_TEST_RUNNER_RULES,$1,$2))
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 186/376 brcmfmac: fix WPA/WPA2-PSK 4-way handshake offload and SAE offload failures
In reply to Greg Kroah-HartmanFrom: Chung-Hsien Hsu <[email protected]>
[ Upstream commit b2fe11f0777311a764e47e2f9437809b4673b7b1 ]
An incorrect value of use_fwsup is set for 4-way handshake offload for WPA//WPA2-PSK, caused by commit 3b1e0a7bdfee ("brcmfmac: add support for SAE authentication offload"). It results in missing bit BRCMF_VIF_STATUS_EAP_SUCCESS set in brcmf_is_linkup() and causes the failure. This patch correct the value for the case.
Also setting bit BRCMF_VIF_STATUS_EAP_SUCCESS for SAE offload case in brcmf_is_linkup() to fix SAE offload failure.
--- .../wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +6 -6
@@ -1819,6 +1819,10 @@ brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)switch (sme->crypto.akm_suites[0 ]) {case WLAN_AKM_SUITE_SAE : val =WPA3_AUTH_SAE_PSK ; +if (sme->crypto.sae_pwd) { +brcmf_dbg (INFO ,"using SAE offload\n" ); + profile->use_fwsup =BRCMF_PROFILE_FWSUP_SAE ; + }break ;default : bphy_err(drvr, "invalid cipher group (%d)\n",
@@ -2104,11 +2108,6 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev, goto done; } -if (sme->crypto.sae_pwd) { -brcmf_dbg (INFO ,"using SAE offload\n" ); - profile->use_fwsup =BRCMF_PROFILE_FWSUP_SAE ; - } -if (sme->crypto.psk && profile->use_fwsup !=BRCMF_PROFILE_FWSUP_SAE ) {if (WARN_ON (profile->use_fwsup !=BRCMF_PROFILE_FWSUP_NONE )) {
@@ -5495,7 +5494,8 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_vif *vif,u32 event = e->event_code;u32 status = e->status; -if (vif->profile.use_fwsup ==BRCMF_PROFILE_FWSUP_PSK && +if ((vif->profile.use_fwsup ==BRCMF_PROFILE_FWSUP_PSK || + vif->profile.use_fwsup ==BRCMF_PROFILE_FWSUP_SAE ) && event ==BRCMF_E_PSK_SUP && status ==BRCMF_E_STATUS_FWSUP_COMPLETED )set_bit (BRCMF_VIF_STATUS_EAP_SUCCESS , &vif->sme_state);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 187/376 md: dont flush workqueue unconditionally in md_open
In reply to Greg Kroah-HartmanFrom: Guoqing Jiang <[email protected]>
[ Upstream commit f6766ff6afff70e2aaf39e1511e16d471de7c3ae ]
We need to check mddev->del_work before flush workqueu since the purpose of flush is to ensure the previous md is disappeared. Otherwise the similar deadlock appeared if LOCKDEP is enabled, it is due to md_open holds the bdev->bd_mutex before flush workqueue.
kernel: [ 154.522645] ======================================================
kernel: [ 154.522647] WARNING: possible circular locking dependency detected
kernel: [ 154.522650] 5.6.0-rc7-lp151.27-default #25 Tainted: G O
kernel: [ 154.522651] ------------------------------------------------------
kernel: [ 154.522653] mdadm/2482 is trying to acquire lock:
kernel: [ 154.522655] ffff888078529128 ((wq_completion)md_misc){+.+.}, at: flush_workqueue+0x84/0x4b0
kernel: [ 154.522673]
kernel: [ 154.522673] but task is already holding lock:
kernel: [ 154.522675] ffff88804efa9338 (&bdev->bd_mutex){+.+.}, at: __blkdev_get+0x79/0x590
kernel: [ 154.522691]
kernel: [ 154.522691] which lock already depends on the new lock.
kernel: [ 154.522691]
kernel: [ 154.522694]
kernel: [ 154.522694] the existing dependency chain (in reverse order) is:
kernel: [ 154.522696]
kernel: [ 154.522696] -> #4 (&bdev->bd_mutex){+.+.}:
kernel: [ 154.522704] __mutex_lock+0x87/0x950
kernel: [ 154.522706] __blkdev_get+0x79/0x590
kernel: [ 154.522708] blkdev_get+0x65/0x140
kernel: [ 154.522709] blkdev_get_by_dev+0x2f/0x40
kernel: [ 154.522716] lock_rdev+0x3d/0x90 [md_mod]
kernel: [ 154.522719] md_import_device+0xd6/0x1b0 [md_mod]
kernel: [ 154.522723] new_dev_store+0x15e/0x210 [md_mod]
kernel: [ 154.522728] md_attr_store+0x7a/0xc0 [md_mod]
kernel: [ 154.522732] kernfs_fop_write+0x117/0x1b0
kernel: [ 154.522735] vfs_write+0xad/0x1a0
kernel: [ 154.522737] ksys_write+0xa4/0xe0
kernel: [ 154.522745] do_syscall_64+0x64/0x2b0
kernel: [ 154.522748] entry_SYSCALL_64_after_hwframe+0x49/0xbe
kernel: [ 154.522749]
kernel: [ 154.522749] -> #3 (&mddev->reconfig_mutex){+.+.}:
kernel: [ 154.522752] __mutex_lock+0x87/0x950
kernel: [ 154.522756] new_dev_store+0xc9/0x210 [md_mod]
kernel: [ 154.522759] md_attr_store+0x7a/0xc0 [md_mod]
kernel: [ 154.522761] kernfs_fop_write+0x117/0x1b0
kernel: [ 154.522763] vfs_write+0xad/0x1a0
kernel: [ 154.522765] ksys_write+0xa4/0xe0
kernel: [ 154.522767] do_syscall_64+0x64/0x2b0
kernel: [ 154.522769] entry_SYSCALL_64_after_hwframe+0x49/0xbe
kernel: [ 154.522770]
kernel: [ 154.522770] -> #2 (kn->count#253){++++}:
kernel: [ 154.522775] __kernfs_remove+0x253/0x2c0
kernel: [ 154.522778] kernfs_remove+0x1f/0x30
kernel: [ 154.522780] kobject_del+0x28/0x60
kernel: [ 154.522783] mddev_delayed_delete+0x24/0x30 [md_mod]
kernel: [ 154.522786] process_one_work+0x2a7/0x5f0
kernel: [ 154.522788] worker_thread+0x2d/0x3d0
kernel: [ 154.522793] kthread+0x117/0x130
kernel: [ 154.522795] ret_from_fork+0x3a/0x50
kernel: [ 154.522796]
kernel: [ 154.522796] -> #1 ((work_completion)(&mddev->del_work)){+.+.}:
kernel: [ 154.522800] process_one_work+0x27e/0x5f0
kernel: [ 154.522802] worker_thread+0x2d/0x3d0
kernel: [ 154.522804] kthread+0x117/0x130
kernel: [ 154.522806] ret_from_fork+0x3a/0x50
kernel: [ 154.522807]
kernel: [ 154.522807] -> #0 ((wq_completion)md_misc){+.+.}:
kernel: [ 154.522813] __lock_acquire+0x1392/0x1690
kernel: [ 154.522816] lock_acquire+0xb4/0x1a0
kernel: [ 154.522818] flush_workqueue+0xab/0x4b0
kernel: [ 154.522821] md_open+0xb6/0xc0 [md_mod]
kernel: [ 154.522823] __blkdev_get+0xea/0x590
kernel: [ 154.522825] blkdev_get+0x65/0x140
kernel: [ 154.522828] do_dentry_open+0x1d1/0x380
kernel: [ 154.522831] path_openat+0x567/0xcc0
kernel: [ 154.522834] do_filp_open+0x9b/0x110
kernel: [ 154.522836] do_sys_openat2+0x201/0x2a0
kernel: [ 154.522838] do_sys_open+0x57/0x80
kernel: [ 154.522840] do_syscall_64+0x64/0x2b0
kernel: [ 154.522842] entry_SYSCALL_64_after_hwframe+0x49/0xbe
kernel: [ 154.522844]
kernel: [ 154.522844] other info that might help us debug this:
kernel: [ 154.522844]
kernel: [ 154.522846] Chain exists of:
kernel: [ 154.522846] (wq_completion)md_misc --> &mddev->reconfig_mutex --> &bdev->bd_mutex
kernel: [ 154.522846]
kernel: [ 154.522850] Possible unsafe locking scenario:
kernel: [ 154.522850]
kernel: [ 154.522852] CPU0 CPU1
kernel: [ 154.522853] ---- ----
kernel: [ 154.522854] lock(&bdev->bd_mutex);
kernel: [ 154.522856] lock(&mddev->reconfig_mutex);
kernel: [ 154.522858] lock(&bdev->bd_mutex);
kernel: [ 154.522860] lock((wq_completion)md_misc);
kernel: [ 154.522861]
kernel: [ 154.522861] *** DEADLOCK ***
kernel: [ 154.522861]
kernel: [ 154.522864] 1 lock held by mdadm/2482:
kernel: [ 154.522865] #0: ffff88804efa9338 (&bdev->bd_mutex){+.+.}, at: __blkdev_get+0x79/0x590
kernel: [ 154.522868]
kernel: [ 154.522868] stack backtrace:
kernel: [ 154.522873] CPU: 1 PID: 2482 Comm: mdadm Tainted: G O 5.6.0-rc7-lp151.27-default #25
kernel: [ 154.522875] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014
kernel: [ 154.522878] Call Trace:
kernel: [ 154.522881] dump_stack+0x8f/0xcb
kernel: [ 154.522884] check_noncircular+0x194/0x1b0
kernel: [ 154.522888] ? __lock_acquire+0x1392/0x1690
kernel: [ 154.522890] __lock_acquire+0x1392/0x1690
kernel: [ 154.522893] lock_acquire+0xb4/0x1a0
kernel: [ 154.522895] ? flush_workqueue+0x84/0x4b0
kernel: [ 154.522898] flush_workqueue+0xab/0x4b0
kernel: [ 154.522900] ? flush_workqueue+0x84/0x4b0
kernel: [ 154.522905] ? md_open+0xb6/0xc0 [md_mod]
kernel: [ 154.522908] md_open+0xb6/0xc0 [md_mod]
kernel: [ 154.522910] __blkdev_get+0xea/0x590
kernel: [ 154.522912] ? bd_acquire+0xc0/0xc0
kernel: [ 154.522914] blkdev_get+0x65/0x140
kernel: [ 154.522916] ? bd_acquire+0xc0/0xc0
kernel: [ 154.522918] do_dentry_open+0x1d1/0x380
kernel: [ 154.522921] path_openat+0x567/0xcc0
kernel: [ 154.522923] ? __lock_acquire+0x380/0x1690
kernel: [ 154.522926] do_filp_open+0x9b/0x110
kernel: [ 154.522929] ? __alloc_fd+0xe5/0x1f0
kernel: [ 154.522935] ? kmem_cache_alloc+0x28c/0x630
kernel: [ 154.522939] ? do_sys_openat2+0x201/0x2a0
kernel: [ 154.522941] do_sys_openat2+0x201/0x2a0
kernel: [ 154.522944] do_sys_open+0x57/0x80
kernel: [ 154.522946] do_syscall_64+0x64/0x2b0
kernel: [ 154.522948] entry_SYSCALL_64_after_hwframe+0x49/0xbe
kernel: [ 154.522951] RIP: 0033:0x7f98d279d9ae
And md_alloc also flushed the same workqueue, but the thing is different here. Because all the paths call md_alloc don't hold bdev->bd_mutex, and the flush is necessary to avoid race condition, so leave it as it is.
--- drivers/md/md.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/md/md.c +2 -1
@@ -7752,7 +7752,8 @@ static int md_open(struct block_device *bdev, fmode_t mode)*/ mddev_put (mddev);/* Wait until bdev->bd_disk is definitely gone */ -flush_workqueue (md_misc_wq); +if (work_pending (&mddev->del_work)) +flush_workqueue (md_misc_wq);/* Then retry the open from the top */ return -ERESTARTSYS ; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 188/376 raid5: remove gfp flags from scribble_alloc()
In reply to Greg Kroah-HartmanFrom: Coly Li <[email protected]>
[ Upstream commit ba54d4d4d2844c234f1b4692bd8c9e0f833c8a54 ]
Using GFP_NOIO flag to call scribble_alloc() from resize_chunk() does not have the expected behavior. kvmalloc_array() inside scribble_alloc() which receives the GFP_NOIO flag will eventually call kmalloc_node() to allocate physically continuous pages.
Now we have memalloc scope APIs in mddev_suspend()/mddev_resume() to prevent memory reclaim I/Os during raid array suspend context, calling to kvmalloc_array() with GFP_KERNEL flag may avoid deadlock of recursive I/O as expected.
This patch removes the useless gfp flags from parameters list of scribble_alloc(), and call kvmalloc_array() with GFP_KERNEL flag. The incorrect GFP_NOIO flag does not exist anymore.
--- drivers/md/raid5.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
drivers/md/raid5.c +9 -6
@@ -2228,14 +2228,19 @@ static int grow_stripes(struct r5conf *conf, int num)* of the P and Q blocks. */ static int scribble_alloc (struct raid5_percpu *percpu, -int num,int cnt,gfp_t flags) +int num,int cnt) {size_t obj_size =sizeof (struct page *) * (num+2 ) +sizeof (addr_conv_t) * (num+2 );void *scribble; - scribble =kvmalloc_array (cnt, obj_size, flags); +/* +* If here is in raid array suspend context, it is in memalloc noio +* context as well, there is no potential recursive memory reclaim +* I/Os with the GFP_KERNEL flag. +*/ + scribble =kvmalloc_array (cnt, obj_size,GFP_KERNEL );if (!scribble)return -ENOMEM ;
@@ -2267,8 +2272,7 @@ static int resize_chunks(struct r5conf *conf, int new_disks, int new_sectors) percpu =per_cpu_ptr (conf->percpu, cpu); err =scribble_alloc (percpu, new_disks, - new_sectors /STRIPE_SECTORS , -GFP_NOIO ); + new_sectors /STRIPE_SECTORS );if (err)break ; }
@@ -6759,8 +6763,7 @@ static int alloc_scratch_buffer(struct r5conf *conf, struct raid5_percpu *percpu conf->previous_raid_disks), max(conf->chunk_sectors, conf->prev_chunk_sectors) - / STRIPE_SECTORS, - GFP_KERNEL)) { + / STRIPE_SECTORS)) {free_scratch_buffer (conf, percpu);return -ENOMEM ; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 189/376 iocost: dont let vrate run wild while theres no saturation signal
In reply to Greg Kroah-HartmanFrom: Tejun Heo <[email protected]>
[ Upstream commit 81ca627a933063fa63a6d4c66425de822a2ab7f5 ]
When the QoS targets are met and nothing is being throttled, there's no way to tell how saturated the underlying device is - it could be almost entirely idle, at the cusp of saturation or anywhere inbetween. Given that there's no information, it's best to keep vrate as-is in this state. Before 7cd806a9a953 ("iocost: improve nr_lagging handling"), this was the case - if the device isn't missing QoS targets and nothing is being throttled, busy_level was reset to zero.
While fixing nr_lagging handling, 7cd806a9a953 ("iocost: improve nr_lagging handling") broke this. Now, while the device is hitting QoS targets and nothing is being throttled, vrate keeps getting adjusted according to the existing busy_level.
This led to vrate keeping climing till it hits max when there's an IO issuer with limited request concurrency if the vrate started low. vrate starts getting adjusted upwards until the issuer can issue IOs w/o being throttled. From then on, QoS targets keeps getting met and nothing on the system needs throttling and vrate keeps getting increased due to the existing busy_level.
This patch makes the following changes to the busy_level logic.
* Reset busy_level if nr_shortages is zero to avoid the above scenario.
* Make non-zero nr_lagging block lowering nr_level but still clear positive busy_level if there's clear non-saturation signal - QoS targets are met and nr_shortages is non-zero. nr_lagging's role is preventing adjusting vrate upwards while there are long-running commands and it shouldn't keep busy_level positive while there's clear non-saturation signal.
* Restructure code for clarity and add comments.
--- block/blk-iocost.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-)
block/blk-iocost.c +24 -4
@@ -1543,19 +1543,39 @@ skip_surplus_transfers:if (rq_wait_pct >RQ_WAIT_BUSY_PCT || missed_ppm[READ ] > ppm_rthr || missed_ppm[WRITE ] > ppm_wthr) { +/* clearly missing QoS targets, slow down vrate */ ioc->busy_level =max (ioc->busy_level,0 ); ioc->busy_level++; }else if (rq_wait_pct <=RQ_WAIT_BUSY_PCT *UNBUSY_THR_PCT /100 && missed_ppm[READ ] <= ppm_rthr *UNBUSY_THR_PCT /100 && missed_ppm[WRITE ] <= ppm_wthr *UNBUSY_THR_PCT /100 ) { -/* take action iff there is contention */ -if (nr_shortages && !nr_lagging) { +/* QoS targets are being met with >25% margin */ +if (nr_shortages) { +/* +* We're throttling while the device has spare +* capacity. If vrate was being slowed down, stop. +*/ ioc->busy_level =min (ioc->busy_level,0 ); -/* redistribute surpluses first */ -if (!nr_surpluses) + +/* +* If there are IOs spanning multiple periods, wait +* them out before pushing the device harder. If +* there are surpluses, let redistribution work it +* out first. +*/ +if (!nr_lagging && !nr_surpluses) ioc->busy_level--; + }else { +/* +* Nobody is being throttled and the users aren't +* issuing enough IOs to saturate the device. We +* simply don't know how close the device is to +* saturation. Coast. +*/ + ioc->busy_level =0 ; } }else { +/* inside the hysterisis margin, we're good */ ioc->busy_level =0 ; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 190/376 veth: Adjust hard_start offset on redirect XDP frames
In reply to Greg Kroah-HartmanFrom: Jesper Dangaard Brouer <[email protected]>
[ Upstream commit 5c8572251fabc5bb49fd623c064e95a9daf6a3e3 ]
When native XDP redirect into a veth device, the frame arrives in the xdp_frame structure. It is then processed in veth_xdp_rcv_one(), which can run a new XDP bpf_prog on the packet. Doing so requires converting xdp_frame to xdp_buff, but the tricky part is that xdp_frame memory area is located in the top (data_hard_start) memory area that xdp_buff will point into.
The current code tried to protect the xdp_frame area, by assigning xdp_buff.data_hard_start past this memory. This results in 32 bytes less headroom to expand into via BPF-helper bpf_xdp_adjust_head().
This protect step is actually not needed, because BPF-helper bpf_xdp_adjust_head() already reserve this area, and don't allow BPF-prog to expand into it. Thus, it is safe to point data_hard_start directly at xdp_frame memory area.
--- drivers/net/veth.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/net/veth.c +4 -4
@@ -564,13 +564,15 @@ static struct sk_buff *veth_xdp_rcv_one(struct veth_rq *rq, struct veth_stats *stats) {void *hard_start = frame->data - frame->headroom; -void *head = hard_start -sizeof (struct xdp_frame );int len = frame->len, delta =0 ;struct xdp_frame orig_frame;struct bpf_prog *xdp_prog;unsigned int headroom;struct sk_buff *skb; +/* bpf_xdp_adjust_head() assures BPF cannot access xdp_frame area */ + hard_start -=sizeof (struct xdp_frame ); +rcu_read_lock (); xdp_prog =rcu_dereference (rq->xdp_prog);if (likely (xdp_prog)) {
@@ -592,7 +594,6 @@ static struct sk_buff *veth_xdp_rcv_one(struct veth_rq *rq,break ;case XDP_TX : orig_frame = *frame; - xdp.data_hard_start = head; xdp.rxq->mem = frame->mem;if (unlikely (veth_xdp_tx (rq, &xdp, bq) <0 )) {trace_xdp_exception (rq->dev, xdp_prog, act);
@@ -605,7 +606,6 @@ static struct sk_buff *veth_xdp_rcv_one(struct veth_rq *rq, goto xdp_xmit;case XDP_REDIRECT : orig_frame = *frame; - xdp.data_hard_start = head; xdp.rxq->mem = frame->mem;if (xdp_do_redirect (rq->dev, &xdp, xdp_prog)) { frame = &orig_frame;
@@ -629,7 +629,7 @@ static struct sk_buff *veth_xdp_rcv_one(struct veth_rq *rq,rcu_read_unlock (); headroom =sizeof (struct xdp_frame ) + frame->headroom - delta; - skb =veth_build_skb (head, headroom, len,0 ); + skb =veth_build_skb (hard_start, headroom, len,0 );if (!skb) {xdp_return_frame (frame); stats->rx_drops++;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 191/376 crypto: blake2b - Fix clang optimization for ARMv7-M
In reply to Greg Kroah-HartmanFrom: Arnd Bergmann <[email protected]>
[ Upstream commit 0c0408e86dbe8f44d4b27bf42130e8ac905361d6 ]
When building for ARMv7-M, clang-9 or higher tries to unroll some loops, which ends up confusing the register allocator to the point of generating rather bad code and using more than the warning limit for stack frames:
warning: stack frame size of 1200 bytes in function 'blake2b_compress' [-Wframe-larger-than=]
Forcing it to not unroll the final loop avoids this problem.
--- crypto/blake2b_generic.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
crypto/blake2b_generic.c +3 -1
@@ -129,7 +129,9 @@ static void blake2b_compress(struct blake2b_state *S,ROUND (9 );ROUND (10 );ROUND (11 ); - +#ifdef CONFIG_CC_IS_CLANG +#pragma nounroll/* https://bugs.llvm.org/show_bug.cgi?id=45803 */ +#endif for (i =0 ; i <8 ; ++i)S ->h[i] =S ->h[i] ^ v[i] ^ v[i +8 ]; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 192/376 io_uring: allow POLL_ADD with double poll_wait() users
In reply to Greg Kroah-HartmanFrom: Jens Axboe <[email protected]>
[ Upstream commit 18bceab101adde8f38de76016bc77f3f25cf22f4 ]
Some file descriptors use separate waitqueues for their f_ops->poll() handler, most commonly one for read and one for write. The io_uring poll implementation doesn't work with that, as the 2nd poll_wait() call will cause the io_uring poll request to -EINVAL.
This affects (at least) tty devices and /dev/random as well. This is a big problem for event loops where some file descriptors work, and others don't.
With this fix, io_uring handles multiple waitqueues.
--- fs/io_uring.c | 218 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 146 insertions(+), 72 deletions(-)
fs/io_uring.c +146 -72
@@ -4106,27 +4106,6 @@ struct io_poll_table {int error; }; -static void __io_queue_proc (struct io_poll_iocb *poll,struct io_poll_table *pt, -struct wait_queue_head *head) -{ -if (unlikely (poll->head)) { - pt->error = -EINVAL ; -return ; - } - - pt->error =0 ; - poll->head = head; -add_wait_queue (head, &poll->wait); -} - -static void io_async_queue_proc (struct file *file,struct wait_queue_head *head, -struct poll_table_struct *p) -{ - struct io_poll_table *pt = container_of(p, struct io_poll_table, pt); - -__io_queue_proc (&pt->req->apoll->poll, pt, head); -} -static int __io_async_wake (struct io_kiocb *req,struct io_poll_iocb *poll,__poll_t mask,task_work_func_t func) {
@@ -4180,6 +4159,144 @@ static bool io_poll_rewait(struct io_kiocb *req, struct io_poll_iocb *poll)return false; } +static void io_poll_remove_double (struct io_kiocb *req) +{ +struct io_poll_iocb *poll = (struct io_poll_iocb *) req->io; + +lockdep_assert_held (&req->ctx->completion_lock); + +if (poll && poll->head) { +struct wait_queue_head *head = poll->head; + +spin_lock (&head->lock); +list_del_init (&poll->wait.entry); +if (poll->wait.private) +refcount_dec (&req->refs); + poll->head =NULL ; +spin_unlock (&head->lock); + } +} + +static void io_poll_complete (struct io_kiocb *req,__poll_t mask,int error) +{ +struct io_ring_ctx *ctx = req->ctx; + +io_poll_remove_double (req); + req->poll.done = true; +io_cqring_fill_event (req, error ? error :mangle_poll (mask)); +io_commit_cqring (ctx); +} + +static void io_poll_task_handler (struct io_kiocb *req,struct io_kiocb **nxt) +{ +struct io_ring_ctx *ctx = req->ctx; + +if (io_poll_rewait (req, &req->poll)) { +spin_unlock_irq (&ctx->completion_lock); +return ; + } + +hash_del (&req->hash_node); +io_poll_complete (req, req->result,0 ); + req->flags |=REQ_F_COMP_LOCKED ; +io_put_req_find_next (req, nxt); +spin_unlock_irq (&ctx->completion_lock); + +io_cqring_ev_posted (ctx); +} + +static void io_poll_task_func (struct callback_head *cb) +{ + struct io_kiocb *req = container_of(cb, struct io_kiocb, task_work); +struct io_kiocb *nxt =NULL ; + +io_poll_task_handler (req, &nxt); +if (nxt) { +struct io_ring_ctx *ctx = nxt->ctx; + +mutex_lock (&ctx->uring_lock); +__io_queue_sqe (nxt,NULL ); +mutex_unlock (&ctx->uring_lock); + } +} + +static int io_poll_double_wake (struct wait_queue_entry *wait,unsigned mode, +int sync,void *key) +{ +struct io_kiocb *req = wait->private; +struct io_poll_iocb *poll = (struct io_poll_iocb *) req->io; +__poll_t mask =key_to_poll (key); + +/* for instances that support it check for an event match first: */ +if (mask && !(mask & poll->events)) +return 0 ; + +if (req->poll.head) { +bool done; + +spin_lock (&req->poll.head->lock); + done =list_empty (&req->poll.wait.entry); +if (!done) +list_del_init (&req->poll.wait.entry); +spin_unlock (&req->poll.head->lock); +if (!done) +__io_async_wake (req, poll, mask, io_poll_task_func); + } +refcount_dec (&req->refs); +return 1 ; +} + +static void io_init_poll_iocb (struct io_poll_iocb *poll,__poll_t events, +wait_queue_func_t wake_func) +{ + poll->head =NULL ; + poll->done = false; + poll->canceled = false; + poll->events = events; +INIT_LIST_HEAD (&poll->wait.entry); +init_waitqueue_func_entry (&poll->wait, wake_func); +} + +static void __io_queue_proc (struct io_poll_iocb *poll,struct io_poll_table *pt, +struct wait_queue_head *head) +{ +struct io_kiocb *req = pt->req; + +/* +* If poll->head is already set, it's because the file being polled +* uses multiple waitqueues for poll handling (eg one for read, one +* for write). Setup a separate io_poll_iocb if this happens. +*/ +if (unlikely (poll->head)) { +/* already have a 2nd entry, fail a third attempt */ +if (req->io) { + pt->error = -EINVAL ; +return ; + } + poll =kmalloc (sizeof (*poll),GFP_ATOMIC ); +if (!poll) { + pt->error = -ENOMEM ; +return ; + } +io_init_poll_iocb (poll, req->poll.events, io_poll_double_wake); +refcount_inc (&req->refs); + poll->wait.private = req; + req->io = (void *) poll; + } + + pt->error =0 ; + poll->head = head; +add_wait_queue (head, &poll->wait); +} + +static void io_async_queue_proc (struct file *file,struct wait_queue_head *head, +struct poll_table_struct *p) +{ + struct io_poll_table *pt = container_of(p, struct io_poll_table, pt); + +__io_queue_proc (&pt->req->apoll->poll, pt, head); +} +static void io_async_task_func (struct callback_head *cb) { struct io_kiocb *req = container_of(cb, struct io_kiocb, task_work);
@@ -4255,18 +4372,13 @@ static __poll_t __io_arm_poll_handler(struct io_kiocb *req,bool cancel = false; poll->file = req->file; - poll->head =NULL ; - poll->done = poll->canceled = false; - poll->events = mask; +io_init_poll_iocb (poll, mask, wake_func); + poll->wait.private = req; ipt->pt._key = mask; ipt->req = req; ipt->error = -EINVAL ; -INIT_LIST_HEAD (&poll->wait.entry); -init_waitqueue_func_entry (&poll->wait, wake_func); - poll->wait.private = req; - mask =vfs_poll (req->file, &ipt->pt) & poll->events;spin_lock_irq (&ctx->completion_lock);
@@ -4297,6 +4409,7 @@ static bool io_arm_poll_handler(struct io_kiocb *req)struct async_poll *apoll;struct io_poll_table ipt;__poll_t mask, ret; +bool had_io;if (!req->file || !file_can_poll (req->file))return false;
@@ -4311,6 +4424,7 @@ static bool io_arm_poll_handler(struct io_kiocb *req) req->flags |=REQ_F_POLLED ;memcpy (&apoll->work, &req->work,sizeof (req->work)); + had_io = req->io !=NULL ;get_task_struct (current); req->task = current;
@@ -4330,7 +4444,9 @@ static bool io_arm_poll_handler(struct io_kiocb *req) io_async_wake);if (ret) { ipt.error =0 ; - apoll->poll.done = true; +/* only remove double add if we did it here */ +if (!had_io) +io_poll_remove_double (req);spin_unlock_irq (&ctx->completion_lock);memcpy (&req->work, &apoll->work,sizeof (req->work));kfree (apoll);
@@ -4363,6 +4479,7 @@ static bool io_poll_remove_one(struct io_kiocb *req)bool do_complete;if (req->opcode ==IORING_OP_POLL_ADD ) { +io_poll_remove_double (req); do_complete =__io_poll_remove_one (req, &req->poll); }else {struct async_poll *apoll = req->apoll;
@@ -4463,49 +4580,6 @@ static int io_poll_remove(struct io_kiocb *req)return 0 ; } -static void io_poll_complete (struct io_kiocb *req,__poll_t mask,int error) -{ -struct io_ring_ctx *ctx = req->ctx; - - req->poll.done = true; -io_cqring_fill_event (req, error ? error :mangle_poll (mask)); -io_commit_cqring (ctx); -} - -static void io_poll_task_handler (struct io_kiocb *req,struct io_kiocb **nxt) -{ -struct io_ring_ctx *ctx = req->ctx; -struct io_poll_iocb *poll = &req->poll; - -if (io_poll_rewait (req, poll)) { -spin_unlock_irq (&ctx->completion_lock); -return ; - } - -hash_del (&req->hash_node); -io_poll_complete (req, req->result,0 ); - req->flags |=REQ_F_COMP_LOCKED ; -io_put_req_find_next (req, nxt); -spin_unlock_irq (&ctx->completion_lock); - -io_cqring_ev_posted (ctx); -} - -static void io_poll_task_func (struct callback_head *cb) -{ - struct io_kiocb *req = container_of(cb, struct io_kiocb, task_work); -struct io_kiocb *nxt =NULL ; - -io_poll_task_handler (req, &nxt); -if (nxt) { -struct io_ring_ctx *ctx = nxt->ctx; - -mutex_lock (&ctx->uring_lock); -__io_queue_sqe (nxt,NULL ); -mutex_unlock (&ctx->uring_lock); - } -} -static int io_poll_wake (struct wait_queue_entry *wait,unsigned mode,int sync,void *key) {
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 193/376 net/mlx5e: IPoIB, Drop multicast packets that this interface sent
In reply to Greg Kroah-HartmanFrom: Erez Shitrit <[email protected]>
[ Upstream commit 8b46d424a743ddfef8056d5167f13ee7ebd1dcad ]
After enabled loopback packets for IPoIB, we need to drop these packets that this HCA has replicated and came back to the same interface that sent them.
--- drivers/net/ethernet/mellanox/mlx5/core/en_rx.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en_rx.c +12 -3
@@ -1501,6 +1501,7 @@ out:#ifdef CONFIG_MLX5_CORE_IPOIB +#define MLX5_IB_GRH_SGID_OFFSET 8#define MLX5_IB_GRH_DGID_OFFSET 24#define MLX5_GID_SIZE 16
@@ -1514,6 +1515,7 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq,struct net_device *netdev;struct mlx5e_priv *priv;char *pseudo_header; +u32 flags_rqpn;u32 qpn;u8 *dgid;u8 g;
@@ -1535,7 +1537,8 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq, tstamp = &priv->tstamp; stats = &priv->channel_stats[rq->ix].rq; - g = (be32_to_cpu (cqe->flags_rqpn) >>28 ) &3 ; + flags_rqpn =be32_to_cpu (cqe->flags_rqpn); + g = (flags_rqpn >>28 ) &3 ; dgid = skb->data +MLX5_IB_GRH_DGID_OFFSET ;if ((!g) || dgid[0 ] !=0xff ) skb->pkt_type =PACKET_HOST ;
@@ -1544,9 +1547,15 @@ static inline void mlx5i_complete_rx_cqe(struct mlx5e_rq *rq,else skb->pkt_type =PACKET_MULTICAST ; -/* TODO: IB/ipoib: Allow mcast packets from other VFs -* 68996a6e760e5c74654723eeb57bf65628ae87f4 +/* Drop packets that this interface sent, ie multicast packets +* that the HCA has replicated. */ +if (g && (qpn == (flags_rqpn &0xffffff )) && + (memcmp (netdev->dev_addr +4 , skb->data +MLX5_IB_GRH_SGID_OFFSET , +MLX5_GID_SIZE ) ==0 )) { + skb->dev =NULL ; +return ; + }skb_pull (skb,MLX5_IB_GRH_BYTES );
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 194/376 selftests/bpf: Fix test_align verifier log patterns
In reply to Greg Kroah-HartmanFrom: Stanislav Fomichev <[email protected]>
[ Upstream commit 5366d2269139ba8eb6a906d73a0819947e3e4e0a ]
Commit 294f2fc6da27 ("bpf: Verifer, adjust_scalar_min_max_vals to always call update_reg_bounds()") changed the way verifier logs some of its state, adjust the test_align accordingly. Where possible, I tried to not copy-paste the entire log line and resorted to dropping the last closing brace instead.
--- tools/testing/selftests/bpf/test_align.c | 41 ++++++++++++------------ 1 file changed, 21 insertions(+), 20 deletions(-)
tools/testing/selftests/bpf/test_align.c +21 -20
@@ -359,15 +359,15 @@ static struct bpf_align_test tests[] = {* is still (4n), fixed offset is not changed. * Also, we create a new reg->id. */ - {29, "R5_w=pkt(id=4,off=18,r=0,umax_value=2040,var_off=(0x0; 0x7fc))"}, + {29, "R5_w=pkt(id=4,off=18,r=0,umax_value=2040,var_off=(0x0; 0x7fc)"},/* At the time the word size load is performed from R5, * its total fixed offset is NET_IP_ALIGN + reg->off (18) * which is 20. Then the variable offset is (4n), so * the total offset is 4-byte aligned and meets the * load's requirements. */ - {33, "R4=pkt(id=4,off=22,r=22,umax_value=2040,var_off=(0x0; 0x7fc))"}, - {33, "R5=pkt(id=4,off=18,r=22,umax_value=2040,var_off=(0x0; 0x7fc))"}, + {33, "R4=pkt(id=4,off=22,r=22,umax_value=2040,var_off=(0x0; 0x7fc)"}, + {33, "R5=pkt(id=4,off=18,r=22,umax_value=2040,var_off=(0x0; 0x7fc)"}, }, }, {
@@ -410,15 +410,15 @@ static struct bpf_align_test tests[] = {/* Adding 14 makes R6 be (4n+2) */ {9, "R6_w=inv(id=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"},/* Packet pointer has (4n+2) offset */ - {11, "R5_w=pkt(id=1,off=0,r=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"}, - {13, "R4=pkt(id=1,off=4,r=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"}, + {11, "R5_w=pkt(id=1,off=0,r=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc)"}, + {13, "R4=pkt(id=1,off=4,r=0,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc)"},/* At the time the word size load is performed from R5, * its total fixed offset is NET_IP_ALIGN + reg->off (0) * which is 2. Then the variable offset is (4n+2), so * the total offset is 4-byte aligned and meets the * load's requirements. */ - {15, "R5=pkt(id=1,off=0,r=4,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc))"}, + {15, "R5=pkt(id=1,off=0,r=4,umin_value=14,umax_value=1034,var_off=(0x2; 0x7fc)"},/* Newly read value in R6 was shifted left by 2, so has * known alignment of 4. */
@@ -426,15 +426,15 @@ static struct bpf_align_test tests[] = {/* Added (4n) to packet pointer's (4n+2) var_off, giving * another (4n+2). */ - {19, "R5_w=pkt(id=2,off=0,r=0,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc))"}, - {21, "R4=pkt(id=2,off=4,r=0,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc))"}, + {19, "R5_w=pkt(id=2,off=0,r=0,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc)"}, + {21, "R4=pkt(id=2,off=4,r=0,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc)"},/* At the time the word size load is performed from R5, * its total fixed offset is NET_IP_ALIGN + reg->off (0) * which is 2. Then the variable offset is (4n+2), so * the total offset is 4-byte aligned and meets the * load's requirements. */ - {23, "R5=pkt(id=2,off=0,r=4,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc))"}, + {23, "R5=pkt(id=2,off=0,r=4,umin_value=14,umax_value=2054,var_off=(0x2; 0xffc)"}, }, }, {
@@ -469,16 +469,16 @@ static struct bpf_align_test tests[] = { .matches = { {4, "R5_w=pkt_end(id=0,off=0,imm=0)"},/* (ptr - ptr) << 2 == unknown, (4n) */ - {6, "R5_w=inv(id=0,smax_value=9223372036854775804,umax_value=18446744073709551612,var_off=(0x0; 0xfffffffffffffffc))"}, + {6, "R5_w=inv(id=0,smax_value=9223372036854775804,umax_value=18446744073709551612,var_off=(0x0; 0xfffffffffffffffc)"},/* (4n) + 14 == (4n+2). We blow our bounds, because * the add could overflow. */ - {7, "R5_w=inv(id=0,var_off=(0x2; 0xfffffffffffffffc))"}, + {7, "R5_w=inv(id=0,smin_value=-9223372036854775806,smax_value=9223372036854775806,umin_value=2,umax_value=18446744073709551614,var_off=(0x2; 0xfffffffffffffffc)"},/* Checked s>=0 */ - {9, "R5=inv(id=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, + {9, "R5=inv(id=0,umin_value=2,umax_value=9223372034707292158,var_off=(0x2; 0x7fffffff7ffffffc)"},/* packet pointer + nonnegative (4n+2) */ - {11, "R6_w=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, - {13, "R4_w=pkt(id=1,off=4,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, + {11, "R6_w=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372034707292158,var_off=(0x2; 0x7fffffff7ffffffc)"}, + {13, "R4_w=pkt(id=1,off=4,r=0,umin_value=2,umax_value=9223372034707292158,var_off=(0x2; 0x7fffffff7ffffffc)"},/* NET_IP_ALIGN + (4n+2) == (4n), alignment is fine. * We checked the bounds, but it might have been able * to overflow if the packet pointer started in the
@@ -486,7 +486,7 @@ static struct bpf_align_test tests[] = {* So we did not get a 'range' on R6, and the access * attempt will fail. */ - {15, "R6_w=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372036854775806,var_off=(0x2; 0x7ffffffffffffffc))"}, + {15, "R6_w=pkt(id=1,off=0,r=0,umin_value=2,umax_value=9223372034707292158,var_off=(0x2; 0x7fffffff7ffffffc)"}, } }, {
@@ -528,7 +528,7 @@ static struct bpf_align_test tests[] = {/* New unknown value in R7 is (4n) */ {11, "R7_w=inv(id=0,umax_value=1020,var_off=(0x0; 0x3fc))"},/* Subtracting it from R6 blows our unsigned bounds */ - {12, "R6=inv(id=0,smin_value=-1006,smax_value=1034,var_off=(0x2; 0xfffffffffffffffc))"}, + {12, "R6=inv(id=0,smin_value=-1006,smax_value=1034,umin_value=2,umax_value=18446744073709551614,var_off=(0x2; 0xfffffffffffffffc)"},/* Checked s>= 0 */ {14, "R6=inv(id=0,umin_value=2,umax_value=1034,var_off=(0x2; 0x7fc))"},/* At the time the word size load is performed from R5,
@@ -537,7 +537,8 @@ static struct bpf_align_test tests[] = {* the total offset is 4-byte aligned and meets the * load's requirements. */ - {20, "R5=pkt(id=1,off=0,r=4,umin_value=2,umax_value=1034,var_off=(0x2; 0x7fc))"}, + {20, "R5=pkt(id=1,off=0,r=4,umin_value=2,umax_value=1034,var_off=(0x2; 0x7fc)"}, + }, }, {
@@ -579,18 +580,18 @@ static struct bpf_align_test tests[] = {/* Adding 14 makes R6 be (4n+2) */ {11, "R6_w=inv(id=0,umin_value=14,umax_value=74,var_off=(0x2; 0x7c))"},/* Subtracting from packet pointer overflows ubounds */ - {13, "R5_w=pkt(id=1,off=0,r=8,umin_value=18446744073709551542,umax_value=18446744073709551602,var_off=(0xffffffffffffff82; 0x7c))"}, + {13, "R5_w=pkt(id=1,off=0,r=8,umin_value=18446744073709551542,umax_value=18446744073709551602,var_off=(0xffffffffffffff82; 0x7c)"},/* New unknown value in R7 is (4n), >= 76 */ {15, "R7_w=inv(id=0,umin_value=76,umax_value=1096,var_off=(0x0; 0x7fc))"},/* Adding it to packet pointer gives nice bounds again */ - {16, "R5_w=pkt(id=2,off=0,r=0,umin_value=2,umax_value=1082,var_off=(0x2; 0x7fc))"}, + {16, "R5_w=pkt(id=2,off=0,r=0,umin_value=2,umax_value=1082,var_off=(0x2; 0xfffffffc)"},/* At the time the word size load is performed from R5, * its total fixed offset is NET_IP_ALIGN + reg->off (0) * which is 2. Then the variable offset is (4n+2), so * the total offset is 4-byte aligned and meets the * load's requirements. */ - {20, "R5=pkt(id=2,off=0,r=4,umin_value=2,umax_value=1082,var_off=(0x2; 0x7fc))"}, + {20, "R5=pkt(id=2,off=0,r=4,umin_value=2,umax_value=1082,var_off=(0x2; 0xfffffffc)"}, }, }, };
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 195/376 net: ipa: do not clear interrupt in gsi_channel_start()
In reply to Greg Kroah-HartmanFrom: Alex Elder <[email protected]>
[ Upstream commit 195ef57f870070cb02f2f3b99a63d69e8e8f798e ]
In gsi_channel_start() there is harmless-looking comment "Clear the channel's event ring interrupt in case it's pending". The intent was to avoid getting spurious interrupts when first bringing up a channel.
However we now use channel stop/start to implement suspend and resume, and an interrupt pending at the time we resume is actually something we don't want to ignore.
The very first time we bring up the channel we do not expect an interrupt to be pending, and even if it were, the effect would simply be to schedule NAPI on that channel, which would find nothing to do, which is not a problem.
Stop clearing any pending IEOB interrupt in gsi_channel_start(). That leaves one caller of the trivial function gsi_isr_ieob_clear(). Get rid of that function and just open-code it in gsi_isr_ieob() instead.
This fixes a problem where suspend/resume IPA v4.2 would get stuck when resuming after a suspend.
--- drivers/net/ipa/gsi.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-)
drivers/net/ipa/gsi.c +1 -10
@@ -238,11 +238,6 @@ static void gsi_irq_ieob_enable(struct gsi *gsi, u32 evt_ring_id)iowrite32 (val, gsi->virt +GSI_CNTXT_SRC_IEOB_IRQ_MSK_OFFSET ); } -static void gsi_isr_ieob_clear (struct gsi *gsi,u32 mask) -{ -iowrite32 (mask, gsi->virt +GSI_CNTXT_SRC_IEOB_IRQ_CLR_OFFSET ); -} -static void gsi_irq_ieob_disable (struct gsi *gsi,u32 evt_ring_id) {u32 val;
@@ -756,7 +751,6 @@ static void gsi_channel_deprogram(struct gsi_channel *channel)int gsi_channel_start (struct gsi *gsi,u32 channel_id) {struct gsi_channel *channel = &gsi->channel[channel_id]; -u32 evt_ring_id = channel->evt_ring_id;int ret;mutex_lock (&gsi->mutex);
@@ -765,9 +759,6 @@ int gsi_channel_start(struct gsi *gsi, u32 channel_id)mutex_unlock (&gsi->mutex); -/* Clear the channel's event ring interrupt in case it's pending */ -gsi_isr_ieob_clear (gsi,BIT (evt_ring_id)); -gsi_channel_thaw (channel);return ret;
@@ -1071,7 +1062,7 @@ static void gsi_isr_ieob(struct gsi *gsi)u32 event_mask; event_mask =ioread32 (gsi->virt +GSI_CNTXT_SRC_IEOB_IRQ_OFFSET ); -gsi_isr_ieob_clear (gsi, event_mask); +iowrite32 (event_mask, gsi->virt +GSI_CNTXT_SRC_IEOB_IRQ_CLR_OFFSET );while (event_mask) {u32 evt_ring_id =__ffs (event_mask);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 196/376 rtlwifi: Fix a double free in _rtl_usb_tx_urb_setup()
In reply to Greg Kroah-HartmanFrom: Dan Carpenter <[email protected]>
[ Upstream commit beb12813bc75d4a23de43b85ad1c7cb28d27631e ]
Seven years ago we tried to fix a leak but actually introduced a double free instead. It was an understandable mistake because the code was a bit confusing and the free was done in the wrong place. The "skb" pointer is freed in both _rtl_usb_tx_urb_setup() and _rtl_usb_transmit(). The free belongs _rtl_usb_transmit() instead of _rtl_usb_tx_urb_setup() and I've cleaned the code up a bit to hopefully make it more clear.
--- drivers/net/wireless/realtek/rtlwifi/usb.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
drivers/net/wireless/realtek/rtlwifi/usb.c +2 -6
@@ -881,10 +881,8 @@ static struct urb *_rtl_usb_tx_urb_setup(struct ieee80211_hw *hw,WARN_ON (NULL == skb); _urb =usb_alloc_urb (0 ,GFP_ATOMIC ); -if (!_urb) { -kfree_skb (skb); +if (!_urb)return NULL ; - }_rtl_install_trx_info (rtlusb, skb, ep_num);usb_fill_bulk_urb (_urb, rtlusb->udev,usb_sndbulkpipe (rtlusb->udev, ep_num), skb->data, skb->len, _rtl_tx_complete, skb);
@@ -898,7 +896,6 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb,struct rtl_usb *rtlusb =rtl_usbdev (rtl_usbpriv (hw));u32 ep_num;struct urb *_urb =NULL ; -struct sk_buff *_skb =NULL ;WARN_ON (NULL == rtlusb->usb_tx_aggregate_hdl);if (unlikely (IS_USB_STOP (rtlusb))) {
@@ -907,8 +904,7 @@ static void _rtl_usb_transmit(struct ieee80211_hw *hw, struct sk_buff *skb,return ; } ep_num = rtlusb->ep_map.ep_mapping[qnum]; - _skb = skb; - _urb =_rtl_usb_tx_urb_setup (hw, _skb, ep_num); + _urb =_rtl_usb_tx_urb_setup (hw, skb, ep_num);if (unlikely (!_urb)) {pr_err ("Can't allocate urb. Drop skb!\n" );kfree_skb (skb);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 197/376 mwifiex: Fix memory corruption in dump_station
In reply to Greg Kroah-HartmanFrom: Pali Rohár <[email protected]>
[ Upstream commit 3aa42bae9c4d1641aeb36f1a8585cd1d506cf471 ]
The mwifiex_cfg80211_dump_station() uses static variable for iterating over a linked list of all associated stations (when the driver is in UAP role). This has a race condition if .dump_station is called in parallel for multiple interfaces. This corruption can be triggered by registering multiple SSIDs and calling, in parallel for multiple interfaces
iw dev <iface> station dump
[16750.719775] Unable to handle kernel paging request at virtual address dead000000000110 ... [16750.899173] Call trace: [16750.901696] mwifiex_cfg80211_dump_station+0x94/0x100 [mwifiex] [16750.907824] nl80211_dump_station+0xbc/0x278 [cfg80211] [16750.913160] netlink_dump+0xe8/0x320 [16750.916827] netlink_recvmsg+0x1b4/0x338 [16750.920861] ____sys_recvmsg+0x7c/0x2b0 [16750.924801] ___sys_recvmsg+0x70/0x98 [16750.928564] __sys_recvmsg+0x58/0xa0 [16750.932238] __arm64_sys_recvmsg+0x28/0x30 [16750.936453] el0_svc_common.constprop.3+0x90/0x158 [16750.941378] do_el0_svc+0x74/0x90 [16750.944784] el0_sync_handler+0x12c/0x1a8 [16750.948903] el0_sync+0x114/0x140 [16750.952312] Code: f9400003 f907f423 eb02007f 54fffd60 (b9401060) [16750.958583] ---[ end trace c8ad181c2f4b8576 ]---
This patch drops the use of the static iterator, and instead every time the function is called iterates to the idx-th position of the linked-list.
It would be better to convert the code not to use linked list for associated stations storage (since the chip has a limited number of associated stations anyway - it could just be an array). Such a change may be proposed in the future. In the meantime this patch can backported into stable kernels in this simple form.
--- drivers/net/wireless/marvell/mwifiex/cfg80211.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
drivers/net/wireless/marvell/mwifiex/cfg80211.c +6 -8
@@ -1496,7 +1496,8 @@ mwifiex_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *mac, struct station_info *sinfo) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); -static struct mwifiex_sta_node *node; +struct mwifiex_sta_node *node; +int i;if ((GET_BSS_ROLE (priv) ==MWIFIEX_BSS_ROLE_STA ) && priv->media_connected && idx ==0 ) {
@@ -1506,13 +1507,10 @@ mwifiex_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *dev,mwifiex_send_cmd (priv,HOST_CMD_APCMD_STA_LIST , HostCmd_ACT_GEN_GET,0 ,NULL , true); -if (node && (&node->list == &priv->sta_list)) { - node =NULL ; -return -ENOENT ; - } - - node =list_prepare_entry (node, &priv->sta_list, list); -list_for_each_entry_continue (node, &priv->sta_list, list) { + i =0 ; +list_for_each_entry (node, &priv->sta_list, list) { +if (i++ != idx) +continue ;ether_addr_copy (mac, node->mac_addr);return mwifiex_dump_station_info (priv, node, sinfo); }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 198/376 kgdboc: Use a platform device to handle tty drivers showing up late
In reply to Greg Kroah-HartmanFrom: Douglas Anderson <[email protected]>
[ Upstream commit 68e55f61c13842baf825958129698c5371db432c ]
If you build CONFIG_KGDB_SERIAL_CONSOLE into the kernel then you should be able to have KGDB init itself at bootup by specifying the "kgdboc=..." kernel command line parameter. This has worked OK for me for many years, but on a new device I switched to it stopped working.
The problem is that on this new device the serial driver gets its probe deferred. Now when kgdb initializes it can't find the tty driver and when it gives up it never tries again.
We could try to find ways to move up the initialization of the serial driver and such a thing might be worthwhile, but it's nice to be robust against serial drivers that load late. We could move kgdb to init itself later but that penalizes our ability to debug early boot code on systems where the driver inits early. We could roll our own system of detecting when new tty drivers get loaded and then use that to figure out when kgdb can init, but that's ugly.
Instead, let's jump on the -EPROBE_DEFER bandwagon. We'll create a singleton instance of a "kgdboc" platform device. If we can't find our tty device when the singleton "kgdboc" probes we'll return -EPROBE_DEFER which means that the system will call us back later to try again when the tty device might be there.
We won't fully transition all of the kgdboc to a platform device because early kgdb initialization (via the "ekgdboc" kernel command line parameter) still runs before the platform device has been created. The kgdb platform device is merely used as a convenient way to hook into the system's normal probe deferral mechanisms.
As part of this, we'll ever-so-slightly change how the "kgdboc=..." kernel command line parameter works. Previously if you booted up and kgdb couldn't find the tty driver then later reading '/sys/module/kgdboc/parameters/kgdboc' would return a blank string. Now kgdb will keep track of the string that came as part of the command line and give it back to you. It's expected that this should be an OK change.
--- drivers/tty/serial/kgdboc.c | 126 +++++++++++++++++++++++++++++------- 1 file changed, 101 insertions(+), 25 deletions(-)
drivers/tty/serial/kgdboc.c +101 -25
@@ -20,6 +20,7 @@#include <linux/vt_kern.h> #include <linux/input.h> #include <linux/module.h> +#include <linux/platform_device.h> #define MAX_CONFIG_LEN 40
@@ -27,6 +28,7 @@ static struct kgdb_io kgdboc_io_ops;/* -1 = init not run yet, 0 = unconfigured, 1 = configured. */ static int configured =-1 ; +static DEFINE_MUTEX (config_mutex);static char config[MAX_CONFIG_LEN ];static struct kparam_string kps = {
@@ -38,6 +40,8 @@ static int kgdboc_use_kms; /* 1 if we use kernel mode switching */static struct tty_driver *kgdb_tty_driver;static int kgdb_tty_line; +static struct platform_device *kgdboc_pdev; +#ifdef CONFIG_KDB_KEYBOARD static int kgdboc_reset_connect(struct input_handler *handler, struct input_dev *dev,
@@ -133,11 +137,13 @@ static void kgdboc_unregister_kbd(void)static void cleanup_kgdboc (void ) { +if (configured !=1 ) +return ; +if (kgdb_unregister_nmi_console ())return ;kgdboc_unregister_kbd (); -if (configured ==1 ) -kgdb_unregister_io_module (&kgdboc_io_ops); +kgdb_unregister_io_module (&kgdboc_io_ops); }static int configure_kgdboc (void )
@@ -198,20 +204,79 @@ nmi_con_failed:kgdb_unregister_io_module (&kgdboc_io_ops); noconfig:kgdboc_unregister_kbd (); - config[0 ] =0 ; configured =0 ; -cleanup_kgdboc ();return err; } +static int kgdboc_probe (struct platform_device *pdev) +{ +int ret =0 ; + +mutex_lock (&config_mutex); +if (configured !=1 ) { + ret =configure_kgdboc (); + +/* Convert "no device" to "defer" so we'll keep trying */ +if (ret == -ENODEV ) + ret = -EPROBE_DEFER ; + } +mutex_unlock (&config_mutex); + +return ret; +} + +static struct platform_driver kgdboc_platform_driver = { + .probe = kgdboc_probe, + .driver = { + .name ="kgdboc" , + .suppress_bind_attrs = true, + }, +}; +static int __init init_kgdboc (void ) { -/* Already configured? */ -if (configured ==1 ) +int ret; + +/* +* kgdboc is a little bit of an odd "platform_driver". It can be +* up and running long before the platform_driver object is +* created and thus doesn't actually store anything in it. There's +* only one instance of kgdb so anything is stored as global state. +* The platform_driver is only created so that we can leverage the +* kernel's mechanisms (like -EPROBE_DEFER) to call us when our +* underlying tty is ready. Here we init our platform driver and +* then create the single kgdboc instance. +*/ + ret =platform_driver_register (&kgdboc_platform_driver); +if (ret) +return ret; + + kgdboc_pdev =platform_device_alloc ("kgdboc" ,PLATFORM_DEVID_NONE ); +if (!kgdboc_pdev) { + ret = -ENOMEM ; + goto err_did_register; + } + + ret =platform_device_add (kgdboc_pdev); +if (!ret)return 0 ; -return configure_kgdboc (); +platform_device_put (kgdboc_pdev); + +err_did_register: +platform_driver_unregister (&kgdboc_platform_driver); +return ret; +} + +static void exit_kgdboc (void ) +{ +mutex_lock (&config_mutex); +cleanup_kgdboc (); +mutex_unlock (&config_mutex); + +platform_device_unregister (kgdboc_pdev); +platform_driver_unregister (&kgdboc_platform_driver); }static int kgdboc_get_char (void )
@@ -234,24 +299,20 @@ static int param_set_kgdboc_var(const char *kmessage, const struct kernel_param *kp) {size_t len =strlen (kmessage); +int ret =0 ;if (len >=MAX_CONFIG_LEN ) {pr_err ("config string too long\n" );return -ENOSPC ; } -/* Only copy in the string if the init function has not run yet */ -if (configured <0 ) { -strcpy (config, kmessage); -return 0 ; - } -if (kgdb_connected) {pr_err ("Cannot reconfigure while KGDB is connected.\n" ); -return -EBUSY ; } +mutex_lock (&config_mutex); +strcpy (config, kmessage);/* Chop out \n char as a result of echo */ if (len && config[len -1 ] =='\n' )
@@ -260,8 +321,30 @@ static int param_set_kgdboc_var(const char *kmessage,if (configured ==1 )cleanup_kgdboc (); -/* Go and configure with the new params. */ -return configure_kgdboc (); +/* +* Configure with the new params as long as init already ran. +* Note that we can get called before init if someone loads us +* with "modprobe kgdboc kgdboc=..." or if they happen to use the +* the odd syntax of "kgdboc.kgdboc=..." on the kernel command. +*/ +if (configured >=0 ) + ret =configure_kgdboc (); + +/* +* If we couldn't configure then clear out the config. Note that +* specifying an invalid config on the kernel command line vs. +* through sysfs have slightly different behaviors. If we fail +* to configure what was specified on the kernel command line +* we'll leave it in the 'config' and return -EPROBE_DEFER from +* our probe. When specified through sysfs userspace is +* responsible for loading the tty driver before setting up. +*/ +if (ret) + config[0 ] ='\0' ; + +mutex_unlock (&config_mutex); + +return ret; }static int dbg_restore_graphics;
@@ -324,15 +407,8 @@ __setup("kgdboc=", kgdboc_option_setup);/* This is only available if kgdboc is a built in for early debugging */ static int __init kgdboc_early_init (char *opt) { -/* save the first character of the config string because the -* init routine can destroy it. -*/ -char save_ch; -kgdboc_option_setup (opt); - save_ch = config[0 ]; -init_kgdboc (); - config[0 ] = save_ch; +configure_kgdboc ();return 0 ; }
@@ -340,7 +416,7 @@ early_param("ekgdboc", kgdboc_early_init);#endif /* CONFIG_KGDB_SERIAL_CONSOLE */ module_init (init_kgdboc); -module_exit (cleanup_kgdboc); +module_exit (exit_kgdboc);module_param_call (kgdboc, param_set_kgdboc_var, param_get_string, &kps,0644 );MODULE_PARM_DESC (kgdboc,"<serial_device>[,baud]" );MODULE_DESCRIPTION ("KGDB Console TTY Driver" );
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 199/376 x86/boot: Correct relocation destination on old linkers
In reply to Greg Kroah-HartmanFrom: Arvind Sankar <[email protected]>
[ Upstream commit 5214028dd89e49ba27007c3ee475279e584261f0 ]
For the 32-bit kernel, as described in
6d92bc9d483a ("x86/build: Build compressed x86 kernels as PIE"),
pre-2.26 binutils generates R_386_32 relocations in PIE mode. Since the startup code does not perform relocation, any reloc entry with R_386_32 will remain as 0 in the executing code.
Commit
974f221c84b0 ("x86/boot: Move compressed kernel to the end of the
decompression buffer")
added a new symbol _end but did not mark it hidden, which doesn't give the correct offset on older linkers. This causes the compressed kernel to be copied beyond the end of the decompression buffer, rather than flush against it. This region of memory may be reserved or already allocated for other purposes by the bootloader.
Mark _end as hidden to fix. This changes the relocation from R_386_32 to R_386_RELATIVE even on the pre-2.26 binutils.
For 64-bit, this is not strictly necessary, as the 64-bit kernel is only built as PIE if the linker supports -z noreloc-overflow, which implies binutils-2.27+, but for consistency, mark _end as hidden here too.
The below illustrates the before/after impact of the patch using binutils-2.25 and gcc-4.6.4 (locally compiled from source) and QEMU.
Disassembly before patch:
48: 8b 86 60 02 00 00 mov 0x260(%esi),%eax
4e: 2d 00 00 00 00 sub $0x0,%eax
4f: R_386_32 _end
Disassembly after patch:
48: 8b 86 60 02 00 00 mov 0x260(%esi),%eax
4e: 2d 00 f0 76 00 sub $0x76f000,%eax
4f: R_386_RELATIVE *ABS*Dump from extract_kernel before patch:
early console in extract_kernel input_data: 0x0207c098 <--- this is at output + init_size input_len: 0x0074fef1 output: 0x01000000 output_len: 0x00fa63d0 kernel_total_size: 0x0107c000 needed_size: 0x0107c000
Dump from extract_kernel after patch:
early console in extract_kernel input_data: 0x0190d098 <--- this is at output + init_size - _end input_len: 0x0074fef1 output: 0x01000000 output_len: 0x00fa63d0 kernel_total_size: 0x0107c000 needed_size: 0x0107c000
--- arch/x86/boot/compressed/head_32.S | 5 +++-- arch/x86/boot/compressed/head_64.S | 1 + 2 files changed, 4 insertions(+), 2 deletions(-)
arch/x86/boot/compressed/head_32.S +3 -2
@@ -49,16 +49,17 @@ * Position Independent Executable (PIE) so that linker won't optimize * R_386_GOT32X relocation to its fixed symbol address. Older * linkers generate R_386_32 relocations against locally defined symbols, - * _bss, _ebss, _got and _egot, in PIE. It isn't wrong, just less + * _bss, _ebss, _got, _egot and _end, in PIE. It isn't wrong, just less * optimal than R_386_RELATIVE. But the x86 kernel fails to properly handle * R_386_32 relocations when relocating the kernel. To generate - * R_386_RELATIVE relocations, we mark _bss, _ebss, _got and _egot as + * R_386_RELATIVE relocations, we mark _bss, _ebss, _got, _egot and _end as * hidden: */ .hidden _bss .hidden _ebss .hidden _got .hidden _egot + .hidden _end __HEAD SYM_FUNC_START(startup_32)
arch/x86/boot/compressed/head_64.S +1 -0
@@ -42,6 +42,7 @@ .hidden _ebss .hidden _got .hidden _egot + .hidden _end __HEAD .code32
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 200/376 xfs: dont fail verifier on empty attr3 leaf block
In reply to Greg Kroah-HartmanFrom: Brian Foster <[email protected]>
[ Upstream commit f28cef9e4daca11337cb9f144cdebedaab69d78c ]
The attr fork can transition from shortform to leaf format while empty if the first xattr doesn't fit in shortform. While this empty leaf block state is intended to be transient, it is technically not due to the transactional implementation of the xattr set operation.
We historically have a couple of bandaids to work around this problem. The first is to hold the buffer after the format conversion to prevent premature writeback of the empty leaf buffer and the second is to bypass the xattr count check in the verifier during recovery. The latter assumes that the xattr set is also in the log and will be recovered into the buffer soon after the empty leaf buffer is reconstructed. This is not guaranteed, however.
If the filesystem crashes after the format conversion but before the xattr set that induced it, only the format conversion may exist in the log. When recovered, this creates a latent corrupted state on the inode as any subsequent attempts to read the buffer fail due to verifier failure. This includes further attempts to set xattrs on the inode or attempts to destroy the attr fork, which prevents the inode from ever being removed from the unlinked list.
To avoid this condition, accept that an empty attr leaf block is a valid state and remove the count check from the verifier. This means that on rare occasions an attr fork might exist in an unexpected state, but is otherwise consistent and functional. Note that we retain the logic to avoid racing with metadata writeback to reduce the window where this can occur.
--- fs/xfs/libxfs/xfs_attr_leaf.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-)
fs/xfs/libxfs/xfs_attr_leaf.c +7 -8
@@ -308,14 +308,6 @@ xfs_attr3_leaf_verify(if (fa)return fa; -/* -* In recovery there is a transient state where count == 0 is valid -* because we may have transitioned an empty shortform attr to a leaf -* if the attr didn't fit in shortform. -*/ -if (!xfs_log_in_recovery (mp) && ichdr.count ==0 ) -return __this_address; -/* * firstused is the block offset of the first name info structure. * Make sure it doesn't go off the block or crash into the header.
@@ -331,6 +323,13 @@ xfs_attr3_leaf_verify( (char *)bp->b_addr + ichdr.firstused)return __this_address; +/* +* NOTE: This verifier historically failed empty leaf buffers because +* we expect the fork to be in another format. Empty attr fork format +* conversions are possible during xattr set, however, and format +* conversion is not atomic with the xattr set that triggers it. We +* cannot assume leaf blocks are non-empty until that is addressed. +*/ buf_end = (char *)bp->b_addr + mp->m_attr_geo->blksize;for (i =0 , ent = entries; i < ichdr.count; ent++, i++) { fa = xfs_attr3_leaf_verify_entry(mp, buf_end, leaf, &ichdr,
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 201/376 sched: Defend cfs and rt bandwidth quota against overflow
In reply to Greg Kroah-HartmanFrom: Huaixin Chang <[email protected]>
[ Upstream commit d505b8af58912ae1e1a211fabc9995b19bd40828 ]
When users write some huge number into cpu.cfs_quota_us or cpu.rt_runtime_us, overflow might happen during to_ratio() shifts of schedulable checks.
to_ratio() could be altered to avoid unnecessary internal overflow, but min_cfs_quota_period is less than 1 << BW_SHIFT, so a cutoff would still be needed. Set a cap MAX_BW for cfs_quota_us and rt_runtime_us to prevent overflow.
--- kernel/sched/core.c | 8 ++++++++ kernel/sched/rt.c | 12 +++++++++++- kernel/sched/sched.h | 2 ++ 3 files changed, 21 insertions(+), 1 deletion(-)
kernel/sched/core.c +8 -0
@@ -7386,6 +7386,8 @@ static DEFINE_MUTEX(cfs_constraints_mutex);const u64 max_cfs_quota_period =1 *NSEC_PER_SEC ;/* 1s */ static const u64 min_cfs_quota_period =1 *NSEC_PER_MSEC ;/* 1ms */ +/* More than 203 days if BW_SHIFT equals 20. */ +static const u64 max_cfs_runtime =MAX_BW *NSEC_PER_USEC ;static int __cfs_schedulable (struct task_group *tg,u64 period,u64 runtime);
@@ -7413,6 +7415,12 @@ static int tg_set_cfs_bandwidth(struct task_group *tg, u64 period, u64 quota)if (period > max_cfs_quota_period)return -EINVAL ; +/* +* Bound quota to defend quota against overflow during bandwidth shift. +*/ +if (quota !=RUNTIME_INF && quota > max_cfs_runtime) +return -EINVAL ; +/* * Prevent race between setting of cfs_rq->runtime_enabled and * unthrottle_offline_cfs_rqs().
kernel/sched/rt.c +11 -1
@@ -9,6 +9,8 @@int sched_rr_timeslice =RR_TIMESLICE ;int sysctl_sched_rr_timeslice = (MSEC_PER_SEC /HZ ) *RR_TIMESLICE ; +/* More than 4 hours if BW_SHIFT equals 20. */ +static const u64 max_rt_runtime =MAX_BW ;static int do_sched_rt_period_timer (struct rt_bandwidth *rt_b,int overrun);
@@ -2585,6 +2587,12 @@ static int tg_set_rt_bandwidth(struct task_group *tg,if (rt_period ==0 )return -EINVAL ; +/* +* Bound quota to defend quota against overflow during bandwidth shift. +*/ +if (rt_runtime !=RUNTIME_INF && rt_runtime > max_rt_runtime) +return -EINVAL ; +mutex_lock (&rt_constraints_mutex); err =__rt_schedulable (tg, rt_period, rt_runtime);if (err)
@@ -2702,7 +2710,9 @@ static int sched_rt_global_validate(void)return -EINVAL ;if ((sysctl_sched_rt_runtime !=RUNTIME_INF ) && - (sysctl_sched_rt_runtime > sysctl_sched_rt_period)) + ((sysctl_sched_rt_runtime > sysctl_sched_rt_period) || + ((u64 )sysctl_sched_rt_runtime * +NSEC_PER_USEC > max_rt_runtime)))return -EINVAL ;return 0 ;
kernel/sched/sched.h +2 -0
@@ -1918,6 +1918,8 @@ extern void init_dl_inactive_task_timer(struct sched_dl_entity *dl_se);#define BW_SHIFT 20#define BW_UNIT (1 << BW_SHIFT)#define RATIO_SHIFT 8 +#define MAX_BW_BITS (64 - BW_SHIFT) +#define MAX_BW ((1ULL << MAX_BW_BITS) - 1)unsigned long to_ratio (u64 period,u64 runtime);extern void init_entity_runnable_average (struct sched_entity *se);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 202/376 mips: MAAR: Use more precise address mask
In reply to Greg Kroah-HartmanFrom: Serge Semin <[email protected]>
[ Upstream commit bbb5946eb545fab8ad8f46bce8a803e1c0c39d47 ]
Indeed according to the MIPS32 Privileged Resource Architecgture the MAAR pair register address field either takes [12:31] bits for non-XPA systems and [12:55] otherwise. In any case the current address mask is just wrong for 64-bit and 32-bits XPA chips. So lets extend it to 59-bits of physical address value. This shall cover the 64-bits architecture and systems with XPA enabled, and won't cause any problem for non-XPA 32-bit systems, since address values exceeding the architecture specific MAAR mask will be just truncated with setting zeros in the unsupported upper bits.
--- arch/mips/include/asm/mipsregs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/mips/include/asm/mipsregs.h +1 -1
@@ -753,7 +753,7 @@/* MAAR bit definitions */ #define MIPS_MAAR_VH (_U64CAST_(1) << 63) -#define MIPS_MAAR_ADDR ((BIT_ULL(BITS_PER_LONG - 12) - 1) << 12) +#define MIPS_MAAR_ADDR GENMASK_ULL(55, 12)#define MIPS_MAAR_ADDR_SHIFT 12#define MIPS_MAAR_S (_ULCAST_(1) << 1)#define MIPS_MAAR_VL (_ULCAST_(1) << 0)
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 203/376 ice: cleanup vf_id signedness
In reply to Greg Kroah-HartmanFrom: Jesse Brandeburg <[email protected]>
[ Upstream commit 53bb66983f34d4ff0af179fe228e2c55e1e45921 ]
The vf_id variable is dealt with in the code in inconsistent ways of sign usage, preventing compilation with -Werror=sign-compare. Fix this problem in the code by always treating vf_id as unsigned, since there are no valid values of vf_id that are negative.
--- drivers/net/ethernet/intel/ice/ice.h | 2 +- .../net/ethernet/intel/ice/ice_virtchnl_pf.c | 17 +++++++++-------- .../net/ethernet/intel/ice/ice_virtchnl_pf.h | 2 +- 3 files changed, 11 insertions(+), 10 deletions(-)
drivers/net/ethernet/intel/ice/ice.h +1 -1
@@ -366,7 +366,7 @@ struct ice_pf {struct ice_sw *first_sw;/* first switch created by firmware */ /* Virtchnl/SR-IOV config info */ struct ice_vf *vf; -int num_alloc_vfs;/* actual number of VFs allocated */ +u16 num_alloc_vfs;/* actual number of VFs allocated */ u16 num_vfs_supported;/* num VFs supported for this PF */ u16 num_qps_per_vf;u16 num_msix_per_vf;
drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +9 -8
@@ -10,10 +10,11 @@* @pf: pointer to the PF structure * @vf_id: the ID of the VF to check */ -static int ice_validate_vf_id (struct ice_pf *pf,int vf_id) +static int ice_validate_vf_id (struct ice_pf *pf,u16 vf_id) { +/* vf_id range is only valid for 0-255, and should always be unsigned */ if (vf_id >= pf->num_alloc_vfs) { -dev_err (ice_pf_to_dev (pf),"Invalid VF ID: %d\n" , vf_id); +dev_err (ice_pf_to_dev (pf),"Invalid VF ID: %u\n" , vf_id);return -EINVAL ; }return 0 ;
@@ -27,7 +28,7 @@ static int ice_validate_vf_id(struct ice_pf *pf, int vf_id)static int ice_check_vf_init (struct ice_pf *pf,struct ice_vf *vf) {if (!test_bit (ICE_VF_STATE_INIT , vf->vf_states)) { -dev_err (ice_pf_to_dev (pf),"VF ID: %d in reset. Try again.\n" , +dev_err (ice_pf_to_dev (pf),"VF ID: %u in reset. Try again.\n" , vf->vf_id);return -EBUSY ; }
@@ -337,7 +338,7 @@ void ice_free_vfs(struct ice_pf *pf)* before this function ever gets called. */ if (!pci_vfs_assigned (pf->pdev)) { -int vf_id; +unsigned int vf_id;/* Acknowledge VFLR for all VFs. Without this, VFs will fail to * work correctly when SR-IOV gets re-enabled.
@@ -368,9 +369,9 @@ static void ice_trigger_vf_reset(struct ice_vf *vf, bool is_vflr, bool is_pfr) {struct ice_pf *pf = vf->pf;u32 reg, reg_idx, bit_idx; +unsigned int vf_abs_id, i;struct device *dev;struct ice_hw *hw; -int vf_abs_id, i; dev =ice_pf_to_dev (pf); hw = &pf->hw;
@@ -418,7 +419,7 @@ static void ice_trigger_vf_reset(struct ice_vf *vf, bool is_vflr, bool is_pfr)if ((reg &VF_TRANS_PENDING_M ) ==0 )break ; -dev_err (dev,"VF %d PCI transactions stuck\n" , vf->vf_id); +dev_err (dev,"VF %u PCI transactions stuck\n" , vf->vf_id);udelay (ICE_PCI_CIAD_WAIT_DELAY_US ); } }
@@ -1483,7 +1484,7 @@ int ice_sriov_configure(struct pci_dev *pdev, int num_vfs)void ice_process_vflr_event (struct ice_pf *pf) {struct ice_hw *hw = &pf->hw; -int vf_id; +unsigned int vf_id;u32 reg; if (!test_and_clear_bit(__ICE_VFLR_EVENT_PENDING, pf->state) ||
@@ -1524,7 +1525,7 @@ static void ice_vc_reset_vf(struct ice_vf *vf)*/ static struct ice_vf *ice_get_vf_from_pfq (struct ice_pf *pf,u16 pfq) { -int vf_id; +unsigned int vf_id;ice_for_each_vf (pf, vf_id) {struct ice_vf *vf = &pf->vf[vf_id];
drivers/net/ethernet/intel/ice/ice_virtchnl_pf.h +1 -1
@@ -64,7 +64,7 @@ struct ice_mdd_vf_events {struct ice_vf {struct ice_pf *pf; -s16 vf_id;/* VF ID in the PF space */ +u16 vf_id;/* VF ID in the PF space */ u16 lan_vsi_idx;/* index into PF struct */ /* first vector index of this VF in the PF space */ int first_vector_idx;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 204/376 ice: Fix resource leak on early exit from function
In reply to Greg Kroah-HartmanFrom: Eric Joyner <[email protected]>
[ Upstream commit 857a4f0e9f4956fffc0cedcaa2ba187a2e987153 ]
Memory allocated in the ice_add_prof_id_vsig() function wasn't being properly freed if an error occurred inside the for-loop in the function.
In particular, 'p' wasn't being freed if an error occurred before it was added to the resource list at the end of the for-loop.
--- drivers/net/ethernet/intel/ice/ice_flex_pipe.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/ethernet/intel/ice/ice_flex_pipe.c +3 -1
@@ -3705,8 +3705,10 @@ ice_add_prof_id_vsig(struct ice_hw *hw, enum ice_block blk, u16 vsig, u64 hdl, t->tcam[i].prof_id, t->tcam[i].ptg, vsig,0 ,0 , vl_msk, dc_msk, nm_msk); -if (status) +if (status) { +devm_kfree (ice_hw_to_dev (hw), p); goto err_ice_add_prof_id_vsig; + }/* log change */ list_add (&p->list_entry, chg);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 205/376 mips: Add udelay lpj numbers adjustment
In reply to Greg Kroah-HartmanFrom: Serge Semin <[email protected]>
[ Upstream commit ed26aacfb5f71eecb20a51c4467da440cb719d66 ]
Loops-per-jiffies is a special number which represents a number of noop-loop cycles per CPU-scheduler quantum - jiffies. As you understand aside from CPU-specific implementation it depends on the CPU frequency. So when a platform has the CPU frequency fixed, we have no problem and the current udelay interface will work just fine. But as soon as CPU-freq driver is enabled and the cores frequency changes, we'll end up with distorted udelay's. In order to fix this we have to accordinly adjust the per-CPU udelay_val (the same as the global loops_per_jiffy) number. This can be done in the CPU-freq transition event handler. We subscribe to that event in the MIPS arch time-inititalization method.
--- arch/mips/kernel/time.c | 70 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+)
arch/mips/kernel/time.c +70 -0
@@ -18,12 +18,82 @@#include <linux/smp.h> #include <linux/spinlock.h> #include <linux/export.h> +#include <linux/cpufreq.h> +#include <linux/delay.h> #include <asm/cpu-features.h> #include <asm/cpu-type.h> #include <asm/div64.h> #include <asm/time.h> +#ifdef CONFIG_CPU_FREQ + +static DEFINE_PER_CPU(unsigned long, pcp_lpj_ref); +static DEFINE_PER_CPU(unsigned long, pcp_lpj_ref_freq); +static unsigned long glb_lpj_ref; +static unsigned long glb_lpj_ref_freq; + +static int cpufreq_callback (struct notifier_block *nb, +unsigned long val,void *data) +{ +struct cpufreq_freqs *freq = data; +struct cpumask *cpus = freq->policy->cpus; +unsigned long lpj; +int cpu; + +/* +* Skip lpj numbers adjustment if the CPU-freq transition is safe for +* the loops delay. (Is this possible?) +*/ +if (freq->flags &CPUFREQ_CONST_LOOPS ) +return NOTIFY_OK ; + +/* Save the initial values of the lpjes for future scaling. */ +if (!glb_lpj_ref) { + glb_lpj_ref = boot_cpu_data.udelay_val; + glb_lpj_ref_freq = freq->old; + +for_each_online_cpu (cpu) { +per_cpu (pcp_lpj_ref, cpu) = + cpu_data[cpu].udelay_val; +per_cpu (pcp_lpj_ref_freq, cpu) = freq->old; + } + } + +/* +* Adjust global lpj variable and per-CPU udelay_val number in +* accordance with the new CPU frequency. +*/ +if ((val ==CPUFREQ_PRECHANGE && freq->old < freq->new) || + (val ==CPUFREQ_POSTCHANGE && freq->old > freq->new)) { + loops_per_jiffy =cpufreq_scale (glb_lpj_ref, + glb_lpj_ref_freq, + freq->new); + +for_each_cpu (cpu, cpus) { + lpj =cpufreq_scale (per_cpu (pcp_lpj_ref, cpu), +per_cpu (pcp_lpj_ref_freq, cpu), + freq->new); + cpu_data[cpu].udelay_val = (unsigned int )lpj; + } + } + +return NOTIFY_OK ; +} + +static struct notifier_block cpufreq_notifier = { + .notifier_call = cpufreq_callback, +}; + +static int __init register_cpufreq_notifier (void ) +{ +return cpufreq_register_notifier (&cpufreq_notifier, +CPUFREQ_TRANSITION_NOTIFIER ); +} +core_initcall (register_cpufreq_notifier); + +#endif /* CONFIG_CPU_FREQ */ +/* * forward reference */
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 206/376 crypto: stm32/crc32 - fix ext4 chksum BUG_ON()
In reply to Greg Kroah-HartmanFrom: Nicolas Toromanoff <[email protected]>
[ Upstream commit 49c2c082e00e0bc4f5cbb7c21c7f0f873b35ab09 ]
Allow use of crc_update without prior call to crc_init.
And change (and fix) driver to use CRC device even on unaligned buffers.
--- drivers/crypto/stm32/stm32-crc32.c | 98 +++++++++++++++--------------- 1 file changed, 48 insertions(+), 50 deletions(-)
drivers/crypto/stm32/stm32-crc32.c +48 -50
@@ -28,8 +28,10 @@/* Registers values */ #define CRC_CR_RESET BIT(0) -#define CRC_CR_REVERSE (BIT(7) | BIT(6) | BIT(5))#define CRC_INIT_DEFAULT 0xFFFFFFFF +#define CRC_CR_REV_IN_WORD (BIT(6) | BIT(5)) +#define CRC_CR_REV_IN_BYTE BIT(5) +#define CRC_CR_REV_OUT BIT(7)#define CRC_AUTOSUSPEND_DELAY 50
@@ -38,8 +40,6 @@ struct stm32_crc {struct device *dev;void __iomem *regs;struct clk *clk; -u8 pending_data[sizeof (u32)]; -size_t nb_pending_bytes; };struct stm32_crc_list {
@@ -59,7 +59,6 @@ struct stm32_crc_ctx {struct stm32_crc_desc_ctx {u32 partial;/* crc32c: partial in first 4 bytes of that struct */ -struct stm32_crc *crc; };static int stm32_crc32_cra_init (struct crypto_tfm *tfm)
@@ -99,25 +98,22 @@ static int stm32_crc_init(struct shash_desc *desc)struct stm32_crc *crc;spin_lock_bh (&crc_list.lock); -list_for_each_entry (crc, &crc_list.dev_list, list) { - ctx->crc = crc; -break ; - } + crc = list_first_entry(&crc_list.dev_list, struct stm32_crc, list);spin_unlock_bh (&crc_list.lock); -pm_runtime_get_sync (ctx->crc->dev); +pm_runtime_get_sync (crc->dev);/* Reset, set key, poly and configure in bit reverse mode */ -writel_relaxed (bitrev32 (mctx->key), ctx->crc->regs +CRC_INIT ); -writel_relaxed (bitrev32 (mctx->poly), ctx->crc->regs +CRC_POL ); -writel_relaxed (CRC_CR_RESET |CRC_CR_REVERSE , ctx->crc->regs +CRC_CR ); +writel_relaxed (bitrev32 (mctx->key), crc->regs +CRC_INIT ); +writel_relaxed (bitrev32 (mctx->poly), crc->regs +CRC_POL ); +writel_relaxed (CRC_CR_RESET |CRC_CR_REV_IN_WORD |CRC_CR_REV_OUT , + crc->regs +CRC_CR );/* Store partial result */ - ctx->partial =readl_relaxed (ctx->crc->regs +CRC_DR ); - ctx->crc->nb_pending_bytes =0 ; + ctx->partial =readl_relaxed (crc->regs +CRC_DR ); -pm_runtime_mark_last_busy (ctx->crc->dev); -pm_runtime_put_autosuspend (ctx->crc->dev); +pm_runtime_mark_last_busy (crc->dev); +pm_runtime_put_autosuspend (crc->dev);return 0 ; }
@@ -126,31 +122,49 @@ static int stm32_crc_update(struct shash_desc *desc, const u8 *d8, unsigned int length) {struct stm32_crc_desc_ctx *ctx =shash_desc_ctx (desc); -struct stm32_crc *crc = ctx->crc; -u32 *d32; -unsigned int i; +struct stm32_crc_ctx *mctx =crypto_shash_ctx (desc->tfm); +struct stm32_crc *crc; + +spin_lock_bh (&crc_list.lock); + crc = list_first_entry(&crc_list.dev_list, struct stm32_crc, list); +spin_unlock_bh (&crc_list.lock);pm_runtime_get_sync (crc->dev); -if (unlikely (crc->nb_pending_bytes)) { -while (crc->nb_pending_bytes !=sizeof (u32) && length) { -/* Fill in pending data */ - crc->pending_data[crc->nb_pending_bytes++] = *(d8++); +/* +* Restore previously calculated CRC for this context as init value +* Restore polynomial configuration +* Configure in register for word input data, +* Configure out register in reversed bit mode data. +*/ +writel_relaxed (bitrev32 (ctx->partial), crc->regs +CRC_INIT ); +writel_relaxed (bitrev32 (mctx->poly), crc->regs +CRC_POL ); +writel_relaxed (CRC_CR_RESET |CRC_CR_REV_IN_WORD |CRC_CR_REV_OUT , + crc->regs +CRC_CR ); + +if (d8 !=PTR_ALIGN (d8,sizeof (u32))) { +/* Configure for byte data */ +writel_relaxed (CRC_CR_REV_IN_BYTE |CRC_CR_REV_OUT , + crc->regs +CRC_CR ); +while (d8 !=PTR_ALIGN (d8,sizeof (u32)) && length) { +writeb_relaxed (*d8++, crc->regs +CRC_DR ); length--; } - -if (crc->nb_pending_bytes ==sizeof (u32)) { -/* Process completed pending data */ -writel_relaxed (*(u32 *)crc->pending_data, - crc->regs +CRC_DR ); - crc->nb_pending_bytes =0 ; - } +/* Configure for word data */ +writel_relaxed (CRC_CR_REV_IN_WORD |CRC_CR_REV_OUT , + crc->regs +CRC_CR ); } - d32 = (u32 *)d8; -for (i =0 ; i < length >>2 ; i++) -/* Process 32 bits data */ -writel_relaxed (*(d32++), crc->regs +CRC_DR ); +for (; length >=sizeof (u32); d8 +=sizeof (u32), length -=sizeof (u32)) +writel_relaxed (*((u32 *)d8), crc->regs +CRC_DR ); + +if (length) { +/* Configure for byte data */ +writel_relaxed (CRC_CR_REV_IN_BYTE |CRC_CR_REV_OUT , + crc->regs +CRC_CR ); +while (length--) +writeb_relaxed (*d8++, crc->regs +CRC_DR ); + }/* Store partial result */ ctx->partial =readl_relaxed (crc->regs +CRC_DR );
@@ -158,22 +172,6 @@ static int stm32_crc_update(struct shash_desc *desc, const u8 *d8,pm_runtime_mark_last_busy (crc->dev);pm_runtime_put_autosuspend (crc->dev); -/* Check for pending data (non 32 bits) */ - length &=3 ; -if (likely (!length)) -return 0 ; - -if ((crc->nb_pending_bytes + length) >=sizeof (u32)) { -/* Shall not happen */ -dev_err (crc->dev,"Pending data overflow\n" ); -return -EINVAL ; - } - - d8 = (const u8 *)d32; -for (i =0 ; i < length; i++) -/* Store pending data */ - crc->pending_data[crc->nb_pending_bytes++] = *(d8++); -return 0 ; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 207/376 crypto: stm32/crc32 - fix run-time self test issue.
In reply to Greg Kroah-HartmanFrom: Nicolas Toromanoff <[email protected]>
[ Upstream commit a8cc3128bf2c01c4d448fe17149e87132113b445 ]
Fix wrong crc32 initialisation value:
"alg: shash: stm32_crc32 test failed (wrong result) on test vector 0, cfg="init+update+final aligned buffer"
cra_name="crc32c" expects an init value of 0XFFFFFFFF, cra_name="crc32" expects an init value of 0.
--- drivers/crypto/stm32/stm32-crc32.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/crypto/stm32/stm32-crc32.c +3 -3
@@ -28,10 +28,10 @@/* Registers values */ #define CRC_CR_RESET BIT(0) -#define CRC_INIT_DEFAULT 0xFFFFFFFF#define CRC_CR_REV_IN_WORD (BIT(6) | BIT(5))#define CRC_CR_REV_IN_BYTE BIT(5)#define CRC_CR_REV_OUT BIT(7) +#define CRC32C_INIT_DEFAULT 0xFFFFFFFF#define CRC_AUTOSUSPEND_DELAY 50
@@ -65,7 +65,7 @@ static int stm32_crc32_cra_init(struct crypto_tfm *tfm) {struct stm32_crc_ctx *mctx =crypto_tfm_ctx (tfm); - mctx->key =CRC_INIT_DEFAULT ; + mctx->key =0 ; mctx->poly =CRC32_POLY_LE ;return 0 ; }
@@ -74,7 +74,7 @@ static int stm32_crc32c_cra_init(struct crypto_tfm *tfm) {struct stm32_crc_ctx *mctx =crypto_tfm_ctx (tfm); - mctx->key =CRC_INIT_DEFAULT ; + mctx->key =CRC32C_INIT_DEFAULT ; mctx->poly =CRC32C_POLY_LE ;return 0 ; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 208/376 crypto: stm32/crc32 - fix multi-instance
In reply to Greg Kroah-HartmanFrom: Nicolas Toromanoff <[email protected]>
[ Upstream commit 10b89c43a64eb0d236903b79a3bc9d8f6cbfd9c7 ]
Ensure CRC algorithm is registered only once in crypto framework when there are several instances of CRC devices.
Update the CRC device list management to avoid that only the first CRC instance is used.
--- drivers/crypto/stm32/stm32-crc32.c | 48 ++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 12 deletions(-)
drivers/crypto/stm32/stm32-crc32.c +36 -12
@@ -91,16 +91,29 @@ static int stm32_crc_setkey(struct crypto_shash *tfm, const u8 *key,return 0 ; } -static int stm32_crc_init (struct shash_desc *desc) +static struct stm32_crc *stm32_crc_get_next_crc (void ) { -struct stm32_crc_desc_ctx *ctx =shash_desc_ctx (desc); -struct stm32_crc_ctx *mctx =crypto_shash_ctx (desc->tfm);struct stm32_crc *crc;spin_lock_bh (&crc_list.lock); crc = list_first_entry(&crc_list.dev_list, struct stm32_crc, list); +if (crc) +list_move_tail (&crc->list, &crc_list.dev_list);spin_unlock_bh (&crc_list.lock); +return crc; +} + +static int stm32_crc_init (struct shash_desc *desc) +{ +struct stm32_crc_desc_ctx *ctx =shash_desc_ctx (desc); +struct stm32_crc_ctx *mctx =crypto_shash_ctx (desc->tfm); +struct stm32_crc *crc; + + crc =stm32_crc_get_next_crc (); +if (!crc) +return -ENODEV ; +pm_runtime_get_sync (crc->dev);/* Reset, set key, poly and configure in bit reverse mode */
@@ -125,9 +138,9 @@ static int stm32_crc_update(struct shash_desc *desc, const u8 *d8,struct stm32_crc_ctx *mctx =crypto_shash_ctx (desc->tfm);struct stm32_crc *crc; -spin_lock_bh (&crc_list.lock); - crc = list_first_entry(&crc_list.dev_list, struct stm32_crc, list); -spin_unlock_bh (&crc_list.lock); + crc =stm32_crc_get_next_crc (); +if (!crc) +return -ENODEV ;pm_runtime_get_sync (crc->dev);
@@ -200,6 +213,8 @@ static int stm32_crc_digest(struct shash_desc *desc, const u8 *data,return stm32_crc_init (desc) ?:stm32_crc_finup (desc, data, length, out); } +static unsigned int refcnt; +static DEFINE_MUTEX (refcnt_lock);static struct shash_alg algs[] = {/* CRC-32 */ {
@@ -290,12 +305,18 @@ static int stm32_crc_probe(struct platform_device *pdev)list_add (&crc->list, &crc_list.dev_list);spin_unlock (&crc_list.lock); - ret =crypto_register_shashes (algs,ARRAY_SIZE (algs)); -if (ret) { -dev_err (dev,"Failed to register\n" ); -clk_disable_unprepare (crc->clk); -return ret; +mutex_lock (&refcnt_lock); +if (!refcnt) { + ret =crypto_register_shashes (algs,ARRAY_SIZE (algs)); +if (ret) { +mutex_unlock (&refcnt_lock); +dev_err (dev,"Failed to register\n" ); +clk_disable_unprepare (crc->clk); +return ret; + } } + refcnt++; +mutex_unlock (&refcnt_lock);dev_info (dev,"Initialized\n" );
@@ -316,7 +337,10 @@ static int stm32_crc_remove(struct platform_device *pdev)list_del (&crc->list);spin_unlock (&crc_list.lock); -crypto_unregister_shashes (algs,ARRAY_SIZE (algs)); +mutex_lock (&refcnt_lock); +if (!--refcnt) +crypto_unregister_shashes (algs,ARRAY_SIZE (algs)); +mutex_unlock (&refcnt_lock);pm_runtime_disable (crc->dev);pm_runtime_put_noidle (crc->dev);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 209/376 drm/amd/powerpay: Disable gfxoff when setting manual mode on picasso and raven
In reply to Greg Kroah-HartmanFrom: chen gong <[email protected]>
[ Upstream commit cbd2d08c7463e78d625a69e9db27ad3004cbbd99 ]
[Problem description]
1. Boot up picasso platform, launches desktop, Don't do anything (APU enter into "gfxoff" state)
2. Remote login to platform using SSH, then type the command line:
sudo su -c "echo manual > /sys/class/drm/card0/device/power_dpm_force_performance_level" sudo su -c "echo 2 > /sys/class/drm/card0/device/pp_dpm_sclk" (fix SCLK to 1400MHz)
3. Move the mouse around in Window
4. Phenomenon : The screen frozen
Tester will switch sclk level during glmark2 run time.
APU will enter "gfxoff" state intermittently during glmark2 run time. The system got hanged if fix GFXCLK to 1400MHz when APU is in "gfxoff" state.
[Debug]
1. Fix SCLK to X MHz
1400: screen frozen, screen black, then OS will reboot.
1300: screen frozen.
1200: screen frozen, screen black.
1100: screen frozen, screen black, then OS will reboot.
1000: screen frozen, screen black.
900: screen frozen, screen black, then OS will reboot.
800: Situation Nomal, issue disappear.
700: Situation Nomal, issue disappear.
2. SBIOS setting: AMD CBS --> SMU Debug Options -->SMU Debug --> "GFX DLDO Psm Margin Control":
50 : Situation Nomal, issue disappear.
45 : Situation Nomal, issue disappear.
40 : Situation Nomal, issue disappear.
35 : Situation Nomal, issue disappear.
30 : screen black.
25 : screen frozen, then blurred screen.
20 : screen frozen.
15 : screen black.
10 : screen frozen.
5 : screen frozen, then blurred screen.
3. Disable GFXOFF feature
Situation Nomal, issue disappear.
[Why]
Through a period of time debugging with Sys Eng team and SMU team, Sys Eng team said this is voltage/frequency marginal issue not a F/W or H/W bug. This experiment proves that default targetPsm [for f=1400MHz] is not sufficient when GFXOFF is enabled on Picasso.
SMU team think it is an odd test conditions to force sclk="1400MHz" when GPU is in "gfxoff" state,then wake up the GFX. SCLK should be in the "lowest frequency" when gfxoff.
[How]
Disable gfxoff when setting manual mode.
Enable gfxoff when setting other mode(exiting manual mode) again.
By the way, from the user point of view, now that user switch to manual mode and force SCLK Frequency, he don't want SCLK be controlled by workload.It becomes meaningless to "switch to manual mode" if APU enter "gfxoff" due to lack of workload at this point.
Tips: Same issue observed on Raven.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +9 -0
@@ -383,6 +383,15 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev,return count; } +if (adev->asic_type ==CHIP_RAVEN ) { +if (adev->rev_id <8 ) { +if (current_level !=AMD_DPM_FORCED_LEVEL_MANUAL && level ==AMD_DPM_FORCED_LEVEL_MANUAL ) +amdgpu_gfx_off_ctrl (adev, false); +else if (current_level ==AMD_DPM_FORCED_LEVEL_MANUAL && level !=AMD_DPM_FORCED_LEVEL_MANUAL ) +amdgpu_gfx_off_ctrl (adev, true); + } + } +/* profile_exit setting is valid only when current mode is in profile mode */ if (!(current_level & (AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD | AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK |
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 210/376 drm/amdgpu: Sync with VM root BO when switching VM to CPU update mode
In reply to Greg Kroah-HartmanFrom: Felix Kuehling <[email protected]>
[ Upstream commit 90ca78deb004abe75b5024968a199acb96bb70f9 ]
This fixes an intermittent bug where a root PD clear operation still in progress could overwrite a PDE update done by the CPU, resulting in a VM fault.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +9 -2
@@ -2996,10 +2996,17 @@ int amdgpu_vm_make_compute(struct amdgpu_device *adev, struct amdgpu_vm *vm, !amdgpu_gmc_vram_full_visible(&adev->gmc)), "CPU update of VM recommended only for large BAR system\n"); -if (vm->use_cpu_for_update) +if (vm->use_cpu_for_update) { +/* Sync with last SDMA update/clear before switching to CPU */ + r =amdgpu_bo_sync_wait (vm->root.base.bo, +AMDGPU_FENCE_OWNER_UNDEFINED , true); +if (r) + goto free_idr; + vm->update_funcs = &amdgpu_vm_cpu_funcs; -else + }else { vm->update_funcs = &amdgpu_vm_sdma_funcs; + }dma_fence_put (vm->last_update); vm->last_update =NULL ; vm->is_compute_context = true;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 211/376 selftests/bpf: CONFIG_IPV6_SEG6_BPF required for test_seg6_loop.o
In reply to Greg Kroah-HartmanFrom: Alan Maguire <[email protected]>
[ Upstream commit 3c8e8cf4b18b3a7034fab4c4504fc4b54e4b6195 ]
test_seg6_loop.o uses the helper bpf_lwt_seg6_adjust_srh(); it will not be present if CONFIG_IPV6_SEG6_BPF is not specified.
--- tools/testing/selftests/bpf/config | 1 + 1 file changed, 1 insertion(+)
tools/testing/selftests/bpf/config +1 -0
@@ -25,6 +25,7 @@ CONFIG_XDP_SOCKETS=y CONFIG_FTRACE_SYSCALLS=y CONFIG_IPV6_TUNNEL=y CONFIG_IPV6_GRE=y +CONFIG_IPV6_SEG6_BPF=y CONFIG_NET_FOU=m CONFIG_NET_FOU_IP_TUNNELS=y CONFIG_IPV6_FOU=m
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 212/376 selftests/bpf: CONFIG_LIRC required for test_lirc_mode2.sh
In reply to Greg Kroah-HartmanFrom: Alan Maguire <[email protected]>
[ Upstream commit a5dfaa2ab94057dd75c7911143482a0a85593c14 ]
test_lirc_mode2.sh assumes presence of /sys/class/rc/rc0/lirc*/uevent which will not be present unless CONFIG_LIRC=y
--- tools/testing/selftests/bpf/config | 1 + 1 file changed, 1 insertion(+)
tools/testing/selftests/bpf/config +1 -0
@@ -38,3 +38,4 @@ CONFIG_IPV6_SIT=m CONFIG_BPF_JIT=y CONFIG_BPF_LSM=y CONFIG_SECURITY=y +CONFIG_LIRC=y
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 213/376 ice: Fix Tx timeout when link is toggled on a VFs interface
In reply to Greg Kroah-HartmanFrom: Brett Creeley <[email protected]>
[ Upstream commit 4dc926d3a59e73b8c4adf51b261f1a1bbd48a989 ]
Currently if the iavf is loaded and a VF link transitions from up to down to up again a Tx timeout will be triggered. This happens because Tx/Rx queue interrupts are only enabled when receiving the VIRTCHNL_OP_CONFIG_MAP_IRQ message, which happens on reset or initial iavf driver load, but not when bringing link up. This is problematic because they are disabled on the VIRTCHNL_OP_DISABLE_QUEUES message, which is part of bringing a VF's link down. However, they are not enabled on the VIRTCHNL_OP_ENABLE_QUEUES message, which is part of bringing a VF's link up.
Fix this by re-enabling the VF's Rx and Tx queue interrupts when they were previously configured. This is done by first checking to make sure the previous value in QINT_[R|T]QCTL.MSIX_INDX is not 0, which is used to represent the OICR in the VF's interrupt space. If the MSIX_INDX is non-zero then enable the interrupt by setting the QINT_[R|T]CTL.CAUSE_ENA bit to 1.
--- .../net/ethernet/intel/ice/ice_virtchnl_pf.c | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+)
drivers/net/ethernet/intel/ice/ice_virtchnl_pf.c +48 -0
@@ -2118,6 +2118,52 @@ static bool ice_vc_validate_vqs_bitmaps(struct virtchnl_queue_select *vqs)return true; } +/** +* ice_vf_ena_txq_interrupt - enable Tx queue interrupt via QINT_TQCTL +* @vsi: VSI of the VF to configure +* @q_idx: VF queue index used to determine the queue in the PF's space +*/ +static void ice_vf_ena_txq_interrupt (struct ice_vsi *vsi,u32 q_idx) +{ +struct ice_hw *hw = &vsi->back->hw; +u32 pfq = vsi->txq_map[q_idx]; +u32 reg; + + reg =rd32 (hw,QINT_TQCTL (pfq)); + +/* MSI-X index 0 in the VF's space is always for the OICR, which means +* this is most likely a poll mode VF driver, so don't enable an +* interrupt that was never configured via VIRTCHNL_OP_CONFIG_IRQ_MAP +*/ +if (!(reg &QINT_TQCTL_MSIX_INDX_M )) +return ; + +wr32 (hw,QINT_TQCTL (pfq), reg |QINT_TQCTL_CAUSE_ENA_M ); +} + +/** +* ice_vf_ena_rxq_interrupt - enable Tx queue interrupt via QINT_RQCTL +* @vsi: VSI of the VF to configure +* @q_idx: VF queue index used to determine the queue in the PF's space +*/ +static void ice_vf_ena_rxq_interrupt (struct ice_vsi *vsi,u32 q_idx) +{ +struct ice_hw *hw = &vsi->back->hw; +u32 pfq = vsi->rxq_map[q_idx]; +u32 reg; + + reg =rd32 (hw,QINT_RQCTL (pfq)); + +/* MSI-X index 0 in the VF's space is always for the OICR, which means +* this is most likely a poll mode VF driver, so don't enable an +* interrupt that was never configured via VIRTCHNL_OP_CONFIG_IRQ_MAP +*/ +if (!(reg &QINT_RQCTL_MSIX_INDX_M )) +return ; + +wr32 (hw,QINT_RQCTL (pfq), reg |QINT_RQCTL_CAUSE_ENA_M ); +} +/** * ice_vc_ena_qs_msg * @vf: pointer to the VF info
@@ -2178,6 +2224,7 @@ static int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg) goto error_param; } +ice_vf_ena_rxq_interrupt (vsi, vf_q_id);set_bit (vf_q_id, vf->rxq_ena); }
@@ -2193,6 +2240,7 @@ static int ice_vc_ena_qs_msg(struct ice_vf *vf, u8 *msg)if (test_bit (vf_q_id, vf->txq_ena))continue ; +ice_vf_ena_txq_interrupt (vsi, vf_q_id);set_bit (vf_q_id, vf->txq_ena); }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 214/376 x86/mm: Stop printing BRK addresses
In reply to Greg Kroah-HartmanFrom: Arvind Sankar <[email protected]>
[ Upstream commit 67d631b7c05eff955ccff4139327f0f92a5117e5 ]
This currently leaks kernel physical addresses into userspace.
--- arch/x86/mm/init.c | 2 -- 1 file changed, 2 deletions(-)
arch/x86/mm/init.c +0 -2
@@ -121,8 +121,6 @@ __ref void *alloc_low_pages(unsigned int num) }else { pfn = pgt_buf_end; pgt_buf_end += num; -printk (KERN_DEBUG "BRK [%#010lx, %#010lx] PGTABLE\n" , - pfn <<PAGE_SHIFT , (pgt_buf_end <<PAGE_SHIFT ) -1 ); }for (i =0 ; i < num; i++) {
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 215/376 MIPS: Fix exception handler memcpy()
In reply to Greg Kroah-HartmanFrom: Ben Hutchings <[email protected]>
[ Upstream commit f39293fd37fff74c531b7a52d0459cc77db85e7f ]
The exception handler subroutines are declared as a single char, but when copied to the required addresses the copy length is 0x80.
When range checks are enabled for memcpy() this results in a build failure, with error messages such as:
In file included from arch/mips/mti-malta/malta-init.c:15:
In function 'memcpy',
inlined from 'mips_nmi_setup' at arch/mips/mti-malta/malta-init.c:98:2:include/linux/string.h:376:4: error: call to '__read_overflow2' declared with attribute error: detected read beyond size of object passed as 2nd parameter
376 | __read_overflow2();
| ^~~~~~~~~~~~~~~~~~Change the declarations to use type char[].
--- arch/mips/loongson2ef/common/init.c | 4 ++-- arch/mips/loongson64/init.c | 4 ++-- arch/mips/mti-malta/malta-init.c | 8 ++++---- arch/mips/pistachio/init.c | 8 ++++---- 4 files changed, 12 insertions(+), 12 deletions(-)
arch/mips/loongson2ef/common/init.c +2 -2
@@ -19,10 +19,10 @@ unsigned long __maybe_unused _loongson_addrwincfg_base;static void __init mips_nmi_setup (void ) {void *base; -extern char except_vec_nmi; +extern char except_vec_nmi[]; base = (void *)(CAC_BASE +0x380 ); -memcpy (base, &except_vec_nmi,0x80 ); +memcpy (base, except_vec_nmi,0x80 );flush_icache_range ((unsigned long )base, (unsigned long )base +0x80 ); }
arch/mips/loongson64/init.c +2 -2
@@ -17,10 +17,10 @@static void __init mips_nmi_setup (void ) {void *base; -extern char except_vec_nmi; +extern char except_vec_nmi[]; base = (void *)(CAC_BASE +0x380 ); -memcpy (base, &except_vec_nmi,0x80 ); +memcpy (base, except_vec_nmi,0x80 );flush_icache_range ((unsigned long )base, (unsigned long )base +0x80 ); }
arch/mips/mti-malta/malta-init.c +4 -4
@@ -90,24 +90,24 @@ static void __init console_config(void)static void __init mips_nmi_setup (void ) {void *base; -extern char except_vec_nmi; +extern char except_vec_nmi[]; base = cpu_has_veic ? (void *)(CAC_BASE +0xa80 ) : (void *)(CAC_BASE +0x380 ); -memcpy (base, &except_vec_nmi,0x80 ); +memcpy (base, except_vec_nmi,0x80 );flush_icache_range ((unsigned long )base, (unsigned long )base +0x80 ); }static void __init mips_ejtag_setup (void ) {void *base; -extern char except_vec_ejtag_debug; +extern char except_vec_ejtag_debug[]; base = cpu_has_veic ? (void *)(CAC_BASE +0xa00 ) : (void *)(CAC_BASE +0x300 ); -memcpy (base, &except_vec_ejtag_debug,0x80 ); +memcpy (base, except_vec_ejtag_debug,0x80 );flush_icache_range ((unsigned long )base, (unsigned long )base +0x80 ); }
arch/mips/pistachio/init.c +4 -4
@@ -83,12 +83,12 @@ phys_addr_t mips_cdmm_phys_base(void)static void __init mips_nmi_setup (void ) {void *base; -extern char except_vec_nmi; +extern char except_vec_nmi[]; base = cpu_has_veic ? (void *)(CAC_BASE +0xa80 ) : (void *)(CAC_BASE +0x380 ); -memcpy (base, &except_vec_nmi,0x80 ); +memcpy (base, except_vec_nmi,0x80 );flush_icache_range ((unsigned long )base, (unsigned long )base +0x80 ); }
@@ -96,12 +96,12 @@ static void __init mips_nmi_setup(void)static void __init mips_ejtag_setup (void ) {void *base; -extern char except_vec_ejtag_debug; +extern char except_vec_ejtag_debug[]; base = cpu_has_veic ? (void *)(CAC_BASE +0xa00 ) : (void *)(CAC_BASE +0x300 ); -memcpy (base, &except_vec_ejtag_debug,0x80 ); +memcpy (base, except_vec_ejtag_debug,0x80 );flush_icache_range ((unsigned long )base, (unsigned long )base +0x80 ); }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 216/376 MIPS: tools: Fix resource leak in elf-entry.c
In reply to Greg Kroah-HartmanFrom: Kaige Li <[email protected]>
[ Upstream commit f33a0b941017b9cb5a4e975af198b855b2f2b455 ]
There is a file descriptor resource leak in elf-entry.c, fix this by adding fclose() before return and die.
--- arch/mips/tools/elf-entry.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
arch/mips/tools/elf-entry.c +8 -1
@@ -51,11 +51,14 @@ int main(int argc, const char *argv[]) nread =fread (&hdr,1 ,sizeof (hdr), file);if (nread !=sizeof (hdr)) {perror ("Unable to read input file" ); +fclose (file);return EXIT_FAILURE ; } -if (memcmp (hdr.ehdr32.e_ident,ELFMAG ,SELFMAG )) +if (memcmp (hdr.ehdr32.e_ident,ELFMAG ,SELFMAG )) { +fclose (file);die ("Input is not an ELF\n" ); + }switch (hdr.ehdr32.e_ident[EI_CLASS ]) {case ELFCLASS32 :
@@ -67,6 +70,7 @@ int main(int argc, const char *argv[]) entry =be32toh (hdr.ehdr32.e_entry);break ;default : +fclose (file);die ("Invalid ELF encoding\n" ); }
@@ -83,14 +87,17 @@ int main(int argc, const char *argv[]) entry =be64toh (hdr.ehdr64.e_entry);break ;default : +fclose (file);die ("Invalid ELF encoding\n" ); }break ;default : +fclose (file);die ("Invalid ELF class\n" ); }printf ("0x%016" PRIx64"\n" , entry); +fclose (file);return EXIT_SUCCESS ; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 217/376 m68k: mac: Dont call via_flush_cache() on Mac IIfx
In reply to Greg Kroah-HartmanFrom: Finn Thain <[email protected]>
[ Upstream commit bcc44f6b74106b31f0b0408b70305a40360d63b7 ]
There is no VIA2 chip on the Mac IIfx, so don't call via_flush_cache(). This avoids a boot crash which appeared in v5.4.
printk: console [ttyS0] enabled
printk: bootconsole [debug0] disabled
printk: bootconsole [debug0] disabled
Calibrating delay loop... 9.61 BogoMIPS (lpj=48064)pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 1024 (order: 0, 4096 bytes, linear) Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes, linear)
devtmpfs: initialized
random: get_random_u32 called from bucket_table_alloc.isra.27+0x68/0x194 with crng_init=0
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns futex hash table entries: 256 (order: -1, 3072 bytes, linear)
NET: Registered protocol family 16
Data read fault at 0x00000000 in Super Data (pc=0x8a6a)
BAD KERNEL BUSERR
Oops: 00000000 Modules linked in: PC: [<00008a6a>] via_flush_cache+0x12/0x2c SR: 2700 SP: 01c1fe3c a2: 01c24000 d0: 00001119 d1: 0000000c d2: 00012000 d3: 0000000f d4: 01c06840 d5: 00033b92 a0: 00000000 a1: 00000000
Process swapper (pid: 1, task=01c24000)
Frame format=B ssw=0755 isc=0200 isb=fff7 daddr=00000000 dobuf=01c1fed0 baddr=00008a6e dibuf=0000004e ver=f
Stack from 01c1fec4:
01c1fed0 00007d7e 00010080 01c1fedc 0000792e 00000001 01c1fef4 00006b40
01c80000 00040000 00000006 00000003 01c1ff1c 004a545e 004ff200 00040000
00000000 00000003 01c06840 00033b92 004a5410 004b6c88 01c1ff84 000021e2
00000073 00000003 01c06840 00033b92 0038507a 004bb094 004b6ca8 004b6c88
004b6ca4 004b6c88 000021ae 00020002 00000000 01c0685d 00000000 01c1ffb4
0049f938 00409c85 01c06840 0045bd40 00000073 00000002 00000002 00000000
Call Trace: [<00007d7e>] mac_cache_card_flush+0x12/0x1c
[<00010080>] fix_dnrm+0x2/0x18
[<0000792e>] cache_push+0x46/0x5a
[<00006b40>] arch_dma_prep_coherent+0x60/0x6e
[<00040000>] switched_to_dl+0x76/0xd0
[<004a545e>] dma_atomic_pool_init+0x4e/0x188
[<00040000>] switched_to_dl+0x76/0xd0
[<00033b92>] parse_args+0x0/0x370
[<004a5410>] dma_atomic_pool_init+0x0/0x188
[<000021e2>] do_one_initcall+0x34/0x1be
[<00033b92>] parse_args+0x0/0x370
[<0038507a>] strcpy+0x0/0x1e
[<000021ae>] do_one_initcall+0x0/0x1be
[<00020002>] do_proc_dointvec_conv+0x54/0x74
[<0049f938>] kernel_init_freeable+0x126/0x190
[<0049f94c>] kernel_init_freeable+0x13a/0x190
[<004a5410>] dma_atomic_pool_init+0x0/0x188
[<00041798>] complete+0x0/0x3c
[<000b9b0c>] kfree+0x0/0x20a
[<0038df98>] schedule+0x0/0xd0
[<0038d604>] kernel_init+0x0/0xda
[<0038d610>] kernel_init+0xc/0xda
[<0038d604>] kernel_init+0x0/0xda
[<00002d38>] ret_from_kernel_thread+0xc/0x14
Code: 0000 2079 0048 10da 2279 0048 10c8 d3c8 <1011> 0200 fff7 1280 d1f9 0048 10c8 1010 0000 0008 1080 4e5e 4e75 4e56 0000 2039
Disabling lock debugging due to kernel taint
Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000bThanks to Stan Johnson for capturing the console log and running git bisect.
Git bisect said commit 8e3a68fb55e0 ("dma-mapping: make dma_atomic_pool_init self-contained") is the first "bad" commit. I don't know why. Perhaps mach_l2_flush first became reachable with that commit.
--- arch/m68k/include/asm/mac_via.h | 1 + arch/m68k/mac/config.c | 21 ++------------------- arch/m68k/mac/via.c | 6 +++++- 3 files changed, 8 insertions(+), 20 deletions(-)
arch/m68k/include/asm/mac_via.h +1 -0
@@ -257,6 +257,7 @@ extern int rbv_present,via_alt_mapping;struct irq_desc ; +extern void via_l2_flush (int writeback);extern void via_register_interrupts (void );extern void via_irq_enable (int );extern void via_irq_disable (int );
arch/m68k/mac/config.c +2 -19
@@ -59,7 +59,6 @@ extern void iop_preinit(void);extern void iop_init (void );extern void via_init (void );extern void via_init_clock (irq_handler_t func); -extern void via_flush_cache (void );extern void oss_init (void );extern void psc_init (void );extern void baboon_init (void );
@@ -130,21 +129,6 @@ int __init mac_parse_bootinfo(const struct bi_record *record)return unknown; } -/* -* Flip into 24bit mode for an instant - flushes the L2 cache card. We -* have to disable interrupts for this. Our IRQ handlers will crap -* themselves if they take an IRQ in 24bit mode! -*/ - -static void mac_cache_card_flush (int writeback) -{ -unsigned long flags; - -local_irq_save (flags); -via_flush_cache (); -local_irq_restore (flags); -} -void __init config_mac (void ) {if (!MACH_IS_MAC )
@@ -175,9 +159,8 @@ void __init config_mac(void)* not. */ -if (macintosh_config->ident ==MAC_MODEL_IICI - || macintosh_config->ident ==MAC_MODEL_IIFX ) - mach_l2_flush = mac_cache_card_flush; +if (macintosh_config->ident ==MAC_MODEL_IICI ) + mach_l2_flush = via_l2_flush; }
arch/m68k/mac/via.c +5 -1
@@ -294,10 +294,14 @@ void via_debug_dump(void)* the system into 24-bit mode for an instant. */ -void via_flush_cache (void ) +void via_l2_flush (int writeback) { +unsigned long flags; + +local_irq_save (flags); via2[gBufB] &= ~VIA2B_vMode32; via2[gBufB] |= VIA2B_vMode32; +local_irq_restore (flags); }/*
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 218/376 btrfs: improve global reserve stealing logic
In reply to Greg Kroah-HartmanFrom: Josef Bacik <[email protected]>
[ Upstream commit 7f9fe614407692f670601a634621138233ac00d7 ]
For unlink transactions and block group removal btrfs_start_transaction_fallback_global_rsv will first try to start an ordinary transaction and if it fails it will fall back to reserving the required amount by stealing from the global reserve. This is problematic because of all the same reasons we had with previous iterations of the ENOSPC handling, thundering herd. We get a bunch of failures all at once, everybody tries to allocate from the global reserve, some win and some lose, we get an ENSOPC.
Fix this behavior by introducing BTRFS_RESERVE_FLUSH_ALL_STEAL. It's used to mark unlink reservation. To fix this we need to integrate this logic into the normal ENOSPC infrastructure. We still go through all of the normal flushing work, and at the moment we begin to fail all the tickets we try to satisfy any tickets that are allowed to steal by stealing from the global reserve. If this works we start the flushing system over again just like we would with a normal ticket satisfaction. This serializes our global reserve stealing, so we don't have the thundering herd problem.
--- fs/btrfs/block-group.c | 2 +- fs/btrfs/ctree.h | 1 + fs/btrfs/inode.c | 2 +- fs/btrfs/space-info.c | 37 ++++++++++++++++++++++++++++++++++++- fs/btrfs/space-info.h | 1 + fs/btrfs/transaction.c | 42 +++++------------------------------------- fs/btrfs/transaction.h | 3 +-- 7 files changed, 46 insertions(+), 42 deletions(-)
fs/btrfs/block-group.c +1 -1
@@ -1175,7 +1175,7 @@ struct btrfs_trans_handle *btrfs_start_trans_remove_block_group(free_extent_map (em);return btrfs_start_transaction_fallback_global_rsv (fs_info->extent_root, - num_items,1 ); + num_items); }/*
fs/btrfs/ctree.h +1 -0
@@ -2512,6 +2512,7 @@ enum btrfs_reserve_flush_enum {BTRFS_RESERVE_FLUSH_LIMIT ,BTRFS_RESERVE_FLUSH_EVICT ,BTRFS_RESERVE_FLUSH_ALL , + BTRFS_RESERVE_FLUSH_ALL_STEAL, }; enum btrfs_flush_state {
fs/btrfs/inode.c +1 -1
@@ -3618,7 +3618,7 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir)* 1 for the inode ref * 1 for the inode */ -return btrfs_start_transaction_fallback_global_rsv (root,5 ,5 ); +return btrfs_start_transaction_fallback_global_rsv (root,5 ); }static int btrfs_unlink (struct inode *dir,struct dentry *dentry)
fs/btrfs/space-info.c +36 -1
@@ -862,6 +862,34 @@ static inline int need_do_async_reclaim(struct btrfs_fs_info *fs_info, !test_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state)); } +static bool steal_from_global_rsv (struct btrfs_fs_info *fs_info, +struct btrfs_space_info *space_info, +struct reserve_ticket *ticket) +{ +struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv; +u64 min_bytes; + +if (global_rsv->space_info != space_info) +return false; + +spin_lock (&global_rsv->lock); + min_bytes =div_factor (global_rsv->size,5 ); +if (global_rsv->reserved < min_bytes + ticket->bytes) { +spin_unlock (&global_rsv->lock); +return false; + } + global_rsv->reserved -= ticket->bytes; + ticket->bytes =0 ; +list_del_init (&ticket->list); +wake_up (&ticket->wait); + space_info->tickets_id++; +if (global_rsv->reserved < global_rsv->size) + global_rsv->full =0 ; +spin_unlock (&global_rsv->lock); + +return true; +} +/* * maybe_fail_all_tickets - we've exhausted our flushing, start failing tickets * @fs_info - fs_info for this fs
@@ -894,6 +922,10 @@ static bool maybe_fail_all_tickets(struct btrfs_fs_info *fs_info, ticket =list_first_entry (&space_info->tickets, struct reserve_ticket, list); +if (ticket->steal && +steal_from_global_rsv (fs_info, space_info, ticket)) +return true; +/* * may_commit_transaction will avoid committing the transaction * if it doesn't feel like the space reclaimed by the commit
@@ -1110,6 +1142,7 @@ static int handle_reserve_ticket(struct btrfs_fs_info *fs_info,switch (flush) {case BTRFS_RESERVE_FLUSH_ALL : +case BTRFS_RESERVE_FLUSH_ALL_STEAL :wait_reserve_ticket (fs_info, space_info, ticket);break ;case BTRFS_RESERVE_FLUSH_LIMIT :
@@ -1209,7 +1242,9 @@ static int __reserve_metadata_bytes(struct btrfs_fs_info *fs_info, ticket.error =0 ; space_info->reclaim_size += ticket.bytes;init_waitqueue_head (&ticket.wait); -if (flush ==BTRFS_RESERVE_FLUSH_ALL ) { + ticket.steal = (flush ==BTRFS_RESERVE_FLUSH_ALL_STEAL ); +if (flush ==BTRFS_RESERVE_FLUSH_ALL || + flush ==BTRFS_RESERVE_FLUSH_ALL_STEAL ) {list_add_tail (&ticket.list, &space_info->tickets);if (!space_info->flush) { space_info->flush =1 ;
fs/btrfs/space-info.h +1 -0
@@ -78,6 +78,7 @@ struct btrfs_space_info {struct reserve_ticket {u64 bytes;int error; +bool steal;struct list_head list;wait_queue_head_t wait; };
fs/btrfs/transaction.c +5 -37
55 lines not on this page · raw message
fs/btrfs/transaction.h +1 -2
@@ -193,8 +193,7 @@ struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, unsigned int num_items);struct btrfs_trans_handle *btrfs_start_transaction_fallback_global_rsv (struct btrfs_root *root, -unsigned int num_items, -int min_factor); +unsigned int num_items);struct btrfs_trans_handle *btrfs_join_transaction (struct btrfs_root *root);struct btrfs_trans_handle *btrfs_join_transaction_spacecache (struct btrfs_root *root);struct btrfs_trans_handle *btrfs_join_transaction_nostart (struct btrfs_root *root);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 219/376 btrfs: qgroup: mark qgroup inconsistent if were inherting snapshot to a new qgroup
In reply to Greg Kroah-HartmanFrom: Qu Wenruo <[email protected]>
[ Upstream commit cbab8ade585a18c4334b085564d9d046e01a3f70 ]
[BUG]
For the following operation, qgroup is guaranteed to be screwed up due to snapshot adding to a new qgroup:
# mkfs.btrfs -f $dev # mount $dev $mnt # btrfs qgroup en $mnt # btrfs subv create $mnt/src # xfs_io -f -c "pwrite 0 1m" $mnt/src/file # sync # btrfs qgroup create 1/0 $mnt/src # btrfs subv snapshot -i 1/0 $mnt/src $mnt/snapshot # btrfs qgroup show -prce $mnt/src qgroupid rfer excl max_rfer max_excl parent child -------- ---- ---- -------- -------- ------ ----- 0/5 16.00KiB 16.00KiB none none --- --- 0/257 1.02MiB 16.00KiB none none --- --- 0/258 1.02MiB 16.00KiB none none 1/0 --- 1/0 0.00B 0.00B none none --- 0/258 ^^^^^^^^^^^^^^^^^^^^
[CAUSE]
The problem is in btrfs_qgroup_inherit(), we don't have good enough check to determine if the new relation would break the existing accounting.
Unlike btrfs_add_qgroup_relation(), which has proper check to determine if we can do quick update without a rescan, in btrfs_qgroup_inherit() we can even assign a snapshot to multiple qgroups.
[FIX]
Fix it by manually marking qgroup inconsistent for snapshot inheritance.
For subvolume creation, since all its extents are exclusively owned, we don't need to rescan.
In theory, we should call relation check like quick_update_accounting() when doing qgroup inheritance and inform user about qgroup accounting inconsistency.
But we don't have good mechanism to relay that back to the user in the snapshot creation context, thus we can only silently mark the qgroup inconsistent.
Anyway, user shouldn't use qgroup inheritance during snapshot creation, and should add qgroup relationship after snapshot creation by 'btrfs qgroup assign', which has a much better UI to inform user about qgroup inconsistent and kick in rescan automatically.
--- fs/btrfs/qgroup.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
fs/btrfs/qgroup.c +14 -0
@@ -2622,6 +2622,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid,struct btrfs_root *quota_root;struct btrfs_qgroup *srcgroup;struct btrfs_qgroup *dstgroup; +bool need_rescan = false;u32 level_size =0 ;u64 nums;
@@ -2765,6 +2766,13 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid, goto unlock; } ++i_qgroups; + +/* +* If we're doing a snapshot, and adding the snapshot to a new +* qgroup, the numbers are guaranteed to be incorrect. +*/ +if (srcid) + need_rescan = true; }for (i =0 ; i < inherit->num_ref_copies; ++i, i_qgroups +=2 ) {
@@ -2784,6 +2792,9 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid, dst->rfer = src->rfer - level_size; dst->rfer_cmpr = src->rfer_cmpr - level_size; + +/* Manually tweaking numbers certainly needs a rescan */ + need_rescan = true; }for (i =0 ; i < inherit->num_excl_copies; ++i, i_qgroups +=2 ) {struct btrfs_qgroup *src;
@@ -2802,6 +2813,7 @@ int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, u64 srcid, dst->excl = src->excl + level_size; dst->excl_cmpr = src->excl_cmpr + level_size; + need_rescan = true; } unlock:
@@ -2809,6 +2821,8 @@ unlock: out:if (!committing)mutex_unlock (&fs_info->qgroup_ioctl_lock); +if (need_rescan) + fs_info->qgroup_flags |=BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT ;return ret; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 220/376 ACPI: video: Use native backlight on Acer TravelMate 5735Z
In reply to Greg Kroah-HartmanFrom: Paul Menzel <[email protected]>
[ Upstream commit c41c36e900a337b4132b12ccabc97f5578248b44 ]
Currently, changing the brightness of the internal display of the Acer TravelMate 5735Z does not work. Pressing the function keys or changing the slider, GNOME Shell 3.36.2 displays the OSD (five steps), but the brightness does not change.
The Acer TravelMate 5735Z shipped with Windows 7 and as such does not trigger our "win8 ready" heuristic for preferring the native backlight interface.
Still ACPI backlight control doesn't work on this model, where as the native (intel_video) backlight interface does work by adding acpi_backlight=native or acpi_backlight=none to Linux’ command line.
So, add a quirk to force using native backlight control on this model.
--- drivers/acpi/video_detect.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/acpi/video_detect.c +10 -0
@@ -361,6 +361,16 @@ static const struct dmi_system_id video_detect_dmi_table[] = { DMI_MATCH(DMI_BOARD_NAME, "JV50"), }, }, + { + /* https://bugzilla.kernel.org/show_bug.cgi?id=207835 */ + .callback = video_detect_force_native, + .ident = "Acer TravelMate 5735Z", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5735Z"), + DMI_MATCH(DMI_BOARD_NAME, "BA51_MV"), + }, + },/* * Desktops which falsely report a backlight and which our heuristics
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 221/376 net: ethernet: fec: move GPR register offset and bit into DT
In reply to Greg Kroah-HartmanFrom: Fugang Duan <[email protected]>
[ Upstream commit 8a448bf832af537d26aa557d183a16943dce4510 ]
The commit da722186f654 (net: fec: set GPR bit on suspend by DT configuration) set the GPR reigster offset and bit in driver for wake on lan feature.
But it introduces two issues here:
- one SOC has two instances, they have different bit
- different SOCs may have different offset and bit
So to support wake-on-lan feature on other i.MX platforms, it should configure the GPR reigster offset and bit from DT.
So the patch is to improve the commit da722186f654 (net: fec: set GPR bit on suspend by DT configuration) to support multiple ethernet instances on i.MX series.
v2:
* switch back to store the quirks bitmask in driver_data
v3:
* suggested by Sascha Hauer, use a struct fec_devinfo for abstracting differences between different hardware variants, it can give more freedom to describe the differences.
--- drivers/net/ethernet/freescale/fec_main.c | 24 +++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-)
drivers/net/ethernet/freescale/fec_main.c +12 -12
@@ -88,8 +88,6 @@ static void fec_enet_itr_coal_init(struct net_device *ndev);struct fec_devinfo {u32 quirks; -u8 stop_gpr_reg; -u8 stop_gpr_bit; };static const struct fec_devinfo fec_imx25_info = {
@@ -112,8 +110,6 @@ static const struct fec_devinfo fec_imx6q_info = {FEC_QUIRK_HAS_BUFDESC_EX |FEC_QUIRK_HAS_CSUM |FEC_QUIRK_HAS_VLAN |FEC_QUIRK_ERR006358 | FEC_QUIRK_HAS_RACC, - .stop_gpr_reg = 0x34, - .stop_gpr_bit = 27, }; static const struct fec_devinfo fec_mvf600_info = {
@@ -3452,19 +3448,23 @@ static int fec_enet_get_irq_cnt(struct platform_device *pdev) }static int fec_enet_init_stop_mode (struct fec_enet_private *fep, -struct fec_devinfo *dev_info,struct device_node *np) {struct device_node *gpr_np; +u32 out_val[3 ];int ret =0 ; -if (!dev_info) -return 0 ; - - gpr_np =of_parse_phandle (np,"gpr" ,0 ); + gpr_np =of_parse_phandle (np,"fsl,stop-mode" ,0 );if (!gpr_np)return 0 ; + ret =of_property_read_u32_array (np,"fsl,stop-mode" , out_val, +ARRAY_SIZE (out_val)); +if (ret) { +dev_dbg (&fep->pdev->dev,"no stop mode property\n" ); +return ret; + } + fep->stop_gpr.gpr =syscon_node_to_regmap (gpr_np);if (IS_ERR (fep->stop_gpr.gpr)) {dev_err (&fep->pdev->dev,"could not find gpr regmap\n" );
@@ -3473,8 +3473,8 @@ static int fec_enet_init_stop_mode(struct fec_enet_private *fep, goto out; } - fep->stop_gpr.reg = dev_info->stop_gpr_reg; - fep->stop_gpr.bit = dev_info->stop_gpr_bit; + fep->stop_gpr.reg = out_val[1 ]; + fep->stop_gpr.bit = out_val[2 ]; out:of_node_put (gpr_np);
@@ -3551,7 +3551,7 @@ fec_probe(struct platform_device *pdev)if (of_get_property (np,"fsl,magic-packet" ,NULL )) fep->wol_flag |=FEC_WOL_HAS_MAGIC_PACKET ; - ret =fec_enet_init_stop_mode (fep, dev_info, np); + ret =fec_enet_init_stop_mode (fep, np);if (ret) goto failed_stop_mode;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 222/376 nvme-pci: make sure write/poll_queues less or equal then cpu count
In reply to Greg Kroah-HartmanFrom: Weiping Zhang <[email protected]>
[ Upstream commit 9c9e76d5792b121f10c3b8ddbb639617e49197f7 ]
Check module parameter write/poll_queues before using it to catch too large values.
Reproducer:
modprobe -r nvme
modprobe nvme write_queues=nproc
echo $((nproc+1)) > /sys/module/nvme/parameters/write_queues echo 1 > /sys/block/nvme0n1/device/reset_controller
[ 657.069000] ------------[ cut here ]------------ [ 657.069022] WARNING: CPU: 10 PID: 1163 at kernel/irq/affinity.c:390 irq_create_affinity_masks+0x47c/0x4a0 [ 657.069056] dm_region_hash dm_log dm_mod [ 657.069059] CPU: 10 PID: 1163 Comm: kworker/u193:9 Kdump: loaded Tainted: G W 5.6.0+ #8 [ 657.069060] Hardware name: Inspur SA5212M5/YZMB-00882-104, BIOS 4.0.9 08/27/2019 [ 657.069064] Workqueue: nvme-reset-wq nvme_reset_work [nvme] [ 657.069066] RIP: 0010:irq_create_affinity_masks+0x47c/0x4a0 [ 657.069067] Code: fe ff ff 48 c7 c0 b0 89 14 95 48 89 46 20 e9 e9 fb ff ff 31 c0 e9 90 fc ff ff 0f 0b 48 c7 44 24 08 00 00 00 00 e9 e9 fc ff ff <0f> 0b e9 87 fe ff ff 48 8b 7c 24 28 e8 33 a0 80 00 e9 b6 fc ff ff [ 657.069068] RSP: 0018:ffffb505ce1ffc78 EFLAGS: 00010202 [ 657.069069] RAX: 0000000000000060 RBX: ffff9b97921fe5c0 RCX: 0000000000000000 [ 657.069069] RDX: ffff9b67bad80000 RSI: 00000000ffffffa0 RDI: 0000000000000000 [ 657.069070] RBP: 0000000000000000 R08: 0000000000000000 R09: ffff9b97921fe718 [ 657.069070] R10: ffff9b97921fe710 R11: 0000000000000001 R12: 0000000000000064 [ 657.069070] R13: 0000000000000060 R14: 0000000000000000 R15: 0000000000000001 [ 657.069071] FS: 0000000000000000(0000) GS:ffff9b67c0880000(0000) knlGS:0000000000000000 [ 657.069072] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 657.069072] CR2: 0000559eac6fc238 CR3: 000000057860a002 CR4: 00000000007606e0 [ 657.069073] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 657.069073] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 657.069073] PKRU: 55555554 [ 657.069074] Call Trace: [ 657.069080] __pci_enable_msix_range+0x233/0x5a0 [ 657.069085] ? kernfs_put+0xec/0x190 [ 657.069086] pci_alloc_irq_vectors_affinity+0xbb/0x130 [ 657.069089] nvme_reset_work+0x6e6/0xeab [nvme] [ 657.069093] ? __switch_to_asm+0x34/0x70 [ 657.069094] ? __switch_to_asm+0x40/0x70 [ 657.069095] ? nvme_irq_check+0x30/0x30 [nvme] [ 657.069098] process_one_work+0x1a7/0x370 [ 657.069101] worker_thread+0x1c9/0x380 [ 657.069102] ? max_active_store+0x80/0x80 [ 657.069103] kthread+0x112/0x130 [ 657.069104] ? __kthread_parkme+0x70/0x70 [ 657.069105] ret_from_fork+0x35/0x40 [ 657.069106] ---[ end trace f4f06b7d24513d06 ]--- [ 657.077110] nvme nvme0: 95/1/0 default/read/poll queues
--- drivers/nvme/host/pci.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-)
drivers/nvme/host/pci.c +18 -4
@@ -68,14 +68,30 @@ static int io_queue_depth = 1024;module_param_cb (io_queue_depth, &io_queue_depth_ops, &io_queue_depth,0644 );MODULE_PARM_DESC (io_queue_depth,"set io queue depth, should >= 2" ); +static int io_queue_count_set (const char *val,const struct kernel_param *kp) +{ +unsigned int n; +int ret; + + ret =kstrtouint (val,10 , &n); +if (ret !=0 || n >num_possible_cpus ()) +return -EINVAL ; +return param_set_uint (val, kp); +} + +static const struct kernel_param_ops io_queue_count_ops = { + .set = io_queue_count_set, + .get = param_get_uint, +}; +static unsigned int write_queues; -module_param (write_queues, uint,0644 ); +module_param_cb (write_queues, &io_queue_count_ops, &write_queues,0644 );MODULE_PARM_DESC (write_queues,"Number of queues to use for writes. If not set, reads and writes " "will share a queue set." );static unsigned int poll_queues; -module_param (poll_queues, uint,0644 ); +module_param_cb (poll_queues, &io_queue_count_ops, &poll_queues,0644 );MODULE_PARM_DESC (poll_queues,"Number of queues to use for polled IO." );struct nvme_dev ;
@@ -3140,8 +3156,6 @@ static int __init nvme_init(void)BUILD_BUG_ON (sizeof (struct nvme_delete_queue ) !=64 );BUILD_BUG_ON (IRQ_AFFINITY_MAX_SETS <2 ); - write_queues =min (write_queues,num_possible_cpus ()); - poll_queues =min (poll_queues,num_possible_cpus ());return pci_register_driver (&nvme_driver); }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 223/376 nvmet: fix memory leak when removing namespaces and controllers concurrently
In reply to Greg Kroah-HartmanFrom: Sagi Grimberg <[email protected]>
[ Upstream commit 64f5e9cdd711b030b05062c17b2ecfbce890cf4c ]
When removing a namespace, we add an NS_CHANGE async event, however if the controller admin queue is removed after the event was added but not yet processed, we won't free the aens, resulting in the below memory leak [1].
Fix that by moving nvmet_async_event_free to the final controller release after it is detached from subsys->ctrls ensuring no async events are added, and modify it to simply remove all pending aens.
--
$ cat /sys/kernel/debug/kmemleak
unreferenced object 0xffff888c1af2c000 (size 32):
comm "nvmetcli", pid 5164, jiffies 4295220864 (age 6829.924s)
hex dump (first 32 bytes):
28 01 82 3b 8b 88 ff ff 28 01 82 3b 8b 88 ff ff (..;....(..;....
02 00 04 65 76 65 6e 74 5f 66 69 6c 65 00 00 00 ...event_file...
backtrace:
[<00000000217ae580>] nvmet_add_async_event+0x57/0x290 [nvmet]
[<0000000012aa2ea9>] nvmet_ns_changed+0x206/0x300 [nvmet]
[<00000000bb3fd52e>] nvmet_ns_disable+0x367/0x4f0 [nvmet]
[<00000000e91ca9ec>] nvmet_ns_free+0x15/0x180 [nvmet]
[<00000000a15deb52>] config_item_release+0xf1/0x1c0
[<000000007e148432>] configfs_rmdir+0x555/0x7c0
[<00000000f4506ea6>] vfs_rmdir+0x142/0x3c0
[<0000000000acaaf0>] do_rmdir+0x2b2/0x340
[<0000000034d1aa52>] do_syscall_64+0xa5/0x4d0
[<00000000211f13bc>] entry_SYSCALL_64_after_hwframe+0x6a/0xdf--- drivers/nvme/target/core.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-)
drivers/nvme/target/core.c +6 -9
@@ -157,14 +157,12 @@ static void nvmet_async_events_process(struct nvmet_ctrl *ctrl, u16 status)static void nvmet_async_events_free (struct nvmet_ctrl *ctrl) { -struct nvmet_req *req; +struct nvmet_async_event *aen, *tmp;mutex_lock (&ctrl->lock); -while (ctrl->nr_async_event_cmds) { - req = ctrl->async_event_cmds[--ctrl->nr_async_event_cmds]; -mutex_unlock (&ctrl->lock); -nvmet_req_complete (req,NVME_SC_INTERNAL |NVME_SC_DNR ); -mutex_lock (&ctrl->lock); +list_for_each_entry_safe (aen, tmp, &ctrl->async_events, entry) { +list_del (&aen->entry); +kfree (aen); }mutex_unlock (&ctrl->lock); }
@@ -764,10 +762,8 @@ void nvmet_sq_destroy(struct nvmet_sq *sq)* If this is the admin queue, complete all AERs so that our * queue doesn't have outstanding requests on it. */ -if (ctrl && ctrl->sqs && ctrl->sqs[0 ] == sq) { +if (ctrl && ctrl->sqs && ctrl->sqs[0 ] == sq)nvmet_async_events_process (ctrl, status); -nvmet_async_events_free (ctrl); - }percpu_ref_kill_and_confirm (&sq->ref, nvmet_confirm_sq);wait_for_completion (&sq->confirm_done);wait_for_completion (&sq->free_done);
@@ -1357,6 +1353,7 @@ static void nvmet_ctrl_free(struct kref *ref)ida_simple_remove (&cntlid_ida, ctrl->cntlid); +nvmet_async_events_free (ctrl);kfree (ctrl->sqs);kfree (ctrl->cqs);kfree (ctrl->changed_ns_list);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 224/376 macvlan: Skip loopback packets in RX handler
In reply to Greg Kroah-HartmanFrom: Alexander Sverdlin <[email protected]>
[ Upstream commit 81f3dc9349ce0bf7b8447f147f45e70f0a5b36a6 ]
Ignore loopback-originatig packets soon enough and don't try to process L2 header where it doesn't exist. The very similar br_handle_frame() in bridge code performs exactly the same check.
This is an example of such ICMPv6 packet:
skb len=96 headroom=40 headlen=96 tailroom=56 mac=(40,0) net=(40,40) trans=80shinfo(txflags=0 nr_frags=0 gso(size=0 type=0 segs=0)) csum(0xae2e9a2f ip_summed=1 complete_sw=0 valid=0 level=0) hash(0xc97ebd88 sw=1 l4=1) proto=0x86dd pkttype=5 iif=24 dev name=etha01.212 feat=0x0x0000000040005000
skb headroom: 00000000: 00 7c 86 52 84 88 ff ff 00 00 00 00 00 00 08 00 skb headroom: 00000010: 45 00 00 9e 5d 5c 40 00 40 11 33 33 00 00 00 01 skb headroom: 00000020: 02 40 43 80 00 00 86 dd skb linear: 00000000: 60 09 88 bd 00 38 3a ff fe 80 00 00 00 00 00 00 skb linear: 00000010: 00 40 43 ff fe 80 00 00 ff 02 00 00 00 00 00 00 skb linear: 00000020: 00 00 00 00 00 00 00 01 86 00 61 00 40 00 00 2d skb linear: 00000030: 00 00 00 00 00 00 00 00 03 04 40 e0 00 00 01 2c skb linear: 00000040: 00 00 00 78 00 00 00 00 fd 5f 42 68 23 87 a8 81 skb linear: 00000050: 00 00 00 00 00 00 00 00 01 01 02 40 43 80 00 00 skb tailroom: 00000000: ... skb tailroom: 00000010: ... skb tailroom: 00000020: ... skb tailroom: 00000030: ...
Call Trace, how it happens exactly:
...
macvlan_handle_frame+0x321/0x425 [macvlan] ? macvlan_forward_source+0x110/0x110 [macvlan] __netif_receive_skb_core+0x545/0xda0 ? enqueue_task_fair+0xe5/0x8e0 ? __netif_receive_skb_one_core+0x36/0x70 __netif_receive_skb_one_core+0x36/0x70 process_backlog+0x97/0x140 net_rx_action+0x1eb/0x350 ? __hrtimer_run_queues+0x136/0x2e0 __do_softirq+0xe3/0x383 do_softirq_own_stack+0x2a/0x40 </IRQ> do_softirq.part.4+0x4e/0x50 netif_rx_ni+0x60/0xd0 dev_loopback_xmit+0x83/0xf0 ip6_finish_output2+0x575/0x590 [ipv6] ? ip6_cork_release.isra.1+0x64/0x90 [ipv6] ? __ip6_make_skb+0x38d/0x680 [ipv6] ? ip6_output+0x6c/0x140 [ipv6] ip6_output+0x6c/0x140 [ipv6] ip6_send_skb+0x1e/0x60 [ipv6] rawv6_sendmsg+0xc4b/0xe10 [ipv6] ? proc_put_long+0xd0/0xd0 ? rw_copy_check_uvector+0x4e/0x110 ? sock_sendmsg+0x36/0x40 sock_sendmsg+0x36/0x40 ___sys_sendmsg+0x2b6/0x2d0 ? proc_dointvec+0x23/0x30 ? addrconf_sysctl_forward+0x8d/0x250 [ipv6] ? dev_forward_change+0x130/0x130 [ipv6] ? _raw_spin_unlock+0x12/0x30 ? proc_sys_call_handler.isra.14+0x9f/0x110 ? __call_rcu+0x213/0x510 ? get_max_files+0x10/0x10 ? trace_hardirqs_on+0x2c/0xe0 ? __sys_sendmsg+0x63/0xa0 __sys_sendmsg+0x63/0xa0 do_syscall_64+0x6c/0x1e0 entry_SYSCALL_64_after_hwframe+0x49/0xbe
--- drivers/net/macvlan.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/macvlan.c +4 -0
@@ -447,6 +447,10 @@ static rx_handler_result_t macvlan_handle_frame(struct sk_buff **pskb)int ret;rx_handler_result_t handle_res; +/* Packets from dev_loopback_xmit() do not have L2 header, bail out */ +if (unlikely (skb->pkt_type ==PACKET_LOOPBACK )) +return RX_HANDLER_PASS ; + port =macvlan_port_get_rcu (skb->dev);if (is_multicast_ether_addr (eth->h_dest)) {unsigned int hash;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 225/376 PCI: Dont disable decoding when mmio_always_on is set
In reply to Greg Kroah-HartmanFrom: Jiaxun Yang <[email protected]>
[ Upstream commit b6caa1d8c80cb71b6162cb1f1ec13aa655026c9f ]
Don't disable MEM/IO decoding when a device have both non_compliant_bars and mmio_always_on.
That would allow us quirk devices with junk in BARs but can't disable their decoding.
--- drivers/pci/probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pci/probe.c +1 -1
@@ -1822,7 +1822,7 @@ int pci_setup_device(struct pci_dev *dev)/* Device class may be changed after fixup */ class = dev->class >>8 ; -if (dev->non_compliant_bars) { +if (dev->non_compliant_bars && !dev->mmio_always_on) {pci_read_config_word (dev,PCI_COMMAND , &cmd);if (cmd & (PCI_COMMAND_IO |PCI_COMMAND_MEMORY )) {pci_info (dev,"device has non-compliant BARs; disabling IO/MEM decoding\n" );
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 226/376 MIPS: Fix IRQ tracing when call handle_fpe() and handle_msa_fpe()
In reply to Greg Kroah-HartmanFrom: YuanJunQing <[email protected]>
[ Upstream commit 31e1b3efa802f97a17628dde280006c4cee4ce5e ]
Register "a1" is unsaved in this function,
when CONFIG_TRACE_IRQFLAGS is enabled,
the TRACE_IRQS_OFF macro will call trace_hardirqs_off(), and this may change register "a1".
The changed register "a1" as argument will be send to do_fpe() and do_msa_fpe().
--- arch/mips/kernel/genex.S | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/mips/kernel/genex.S +3 -3
@@ -476,20 +476,20 @@ NESTED(nmi_handler, PT_SIZE, sp) .endm .macro __build_clear_fpe + CLI + TRACE_IRQS_OFF .set push /* gas fails to assemble cfc1 for some archs (octeon).*/ \ .set mips1 SET_HARDFLOAT cfc1 a1, fcr31 .set pop - CLI - TRACE_IRQS_OFF .endm .macro __build_clear_msa_fpe - _cfcmsa a1, MSA_CSR CLI TRACE_IRQS_OFF + _cfcmsa a1, MSA_CSR .endm .macro __build_clear_ade
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 227/376 bcache: fix refcount underflow in bcache_device_free()
In reply to Greg Kroah-HartmanFrom: Coly Li <[email protected]>
[ Upstream commit 86da9f736740eba602389908574dfbb0f517baa5 ]
The problematic code piece in bcache_device_free() is,
785 static void bcache_device_free(struct bcache_device *d) 786 {
787 struct gendisk *disk = d->disk;
[snipped]
799 if (disk) {
800 if (disk->flags & GENHD_FL_UP)
801 del_gendisk(disk);
802
803 if (disk->queue)
804 blk_cleanup_queue(disk->queue);
805
806 ida_simple_remove(&bcache_device_idx,
807 first_minor_to_idx(disk->first_minor));
808 put_disk(disk);
809 }
[snipped]
816 }
At line 808, put_disk(disk) may encounter kobject refcount of 'disk' being underflow.
Here is how to reproduce the issue,
- Attche the backing device to a cache device and do random write to make the cache being dirty.
- Stop the bcache device while the cache device has dirty data of the backing device.
- Only register the backing device back, NOT register cache device.
- The bcache device node /dev/bcache0 won't show up, because backing device waits for the cache device shows up for the missing dirty data.
- Now echo 1 into /sys/fs/bcache/pendings_cleanup, to stop the pending backing device.
- After the pending backing device stopped, use 'dmesg' to check kernel message, a use-after-free warning from KASA reported the refcount of kobject linked to the 'disk' is underflow.
The dropping refcount at line 808 in the above code piece is added by add_disk(d->disk) in bch_cached_dev_run(). But in the above condition the cache device is not registered, bch_cached_dev_run() has no chance to be called and the refcount is not added. The put_disk() for a non- added refcount of gendisk kobject triggers a underflow warning.
This patch checks whether GENHD_FL_UP is set in disk->flags, if it is not set then the bcache device was not added, don't call put_disk() and the the underflow issue can be avoided.
--- drivers/md/bcache/super.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/md/bcache/super.c +5 -2
@@ -797,7 +797,9 @@ static void bcache_device_free(struct bcache_device *d)bcache_device_detach (d);if (disk) { -if (disk->flags &GENHD_FL_UP ) +bool disk_added = (disk->flags &GENHD_FL_UP ) !=0 ; + +if (disk_added)del_gendisk (disk);if (disk->queue)
@@ -805,7 +807,8 @@ static void bcache_device_free(struct bcache_device *d)ida_simple_remove (&bcache_device_idx,first_minor_to_idx (disk->first_minor)); -put_disk (disk); +if (disk_added) +put_disk (disk); }bioset_exit (&d->bio_split);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 228/376 mmc: mmci: Switch to mmc_regulator_set_vqmmc()
In reply to Greg Kroah-HartmanFrom: Marek Vasut <[email protected]>
[ Upstream commit 3e09a81e166c0a5544832459be17561a6b231ac7 ]
Instead of reimplementing the logic in mmc_regulator_set_vqmmc(), use the mmc code function directly.
This also allows us to fix a related issue on STM32MP1, when a voltage switch of 1.8V is done for the eMMC, but the current level is already set to 1.8V. More precisely, in this scenario the call to the ->post_sig_volt_switch() hangs, indefinitely waiting for the voltage switch to complete. Fix this problem by checking if mmc_regulator_set_vqmmc() returned 1 and then skip invoking the callback.
--- drivers/mmc/host/mmci.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-)
drivers/mmc/host/mmci.c +8 -22
@@ -1861,31 +1861,17 @@ static int mmci_get_cd(struct mmc_host *mmc)static int mmci_sig_volt_switch (struct mmc_host *mmc,struct mmc_ios *ios) {struct mmci_host *host =mmc_priv (mmc); -int ret =0 ; - -if (!IS_ERR (mmc->supply.vqmmc)) { +int ret; -switch (ios->signal_voltage) { -case MMC_SIGNAL_VOLTAGE_330 : - ret =regulator_set_voltage (mmc->supply.vqmmc, -2700000 ,3600000 ); -break ; -case MMC_SIGNAL_VOLTAGE_180 : - ret =regulator_set_voltage (mmc->supply.vqmmc, -1700000 ,1950000 ); -break ; -case MMC_SIGNAL_VOLTAGE_120 : - ret =regulator_set_voltage (mmc->supply.vqmmc, -1100000 ,1300000 ); -break ; - } + ret =mmc_regulator_set_vqmmc (mmc, ios); -if (!ret && host->ops && host->ops->post_sig_volt_switch) - ret = host->ops->post_sig_volt_switch (host, ios); +if (!ret && host->ops && host->ops->post_sig_volt_switch) + ret = host->ops->post_sig_volt_switch (host, ios); +else if (ret) + ret =0 ; -if (ret) -dev_warn (mmc_dev (mmc),"Voltage switch failed\n" ); - } +if (ret <0 ) +dev_warn (mmc_dev (mmc),"Voltage switch failed\n" );return ret; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 229/376 mmc: sdhci-msm: Set SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 quirk
In reply to Greg Kroah-HartmanFrom: Veerabhadrarao Badiganti <[email protected]>
[ Upstream commit d863cb03fb2aac07f017b2a1d923cdbc35021280 ]
sdhci-msm can support auto cmd12.
So enable SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 quirk.
--- drivers/mmc/host/sdhci-msm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/mmc/host/sdhci-msm.c +3 -1
@@ -1888,7 +1888,9 @@ static const struct sdhci_ops sdhci_msm_ops = {static const struct sdhci_pltfm_data sdhci_msm_pdata = { .quirks =SDHCI_QUIRK_BROKEN_CARD_DETECTION |SDHCI_QUIRK_SINGLE_POWER_WRITE | -SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN , +SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | +SDHCI_QUIRK_MULTIBLOCK_READ_ACMD12 , + .quirks2 =SDHCI_QUIRK2_PRESET_VALUE_BROKEN , .ops = &sdhci_msm_ops, };
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 230/376 staging: greybus: sdio: Respect the cmd->busy_timeout from the mmc core
In reply to Greg Kroah-HartmanFrom: Ulf Hansson <[email protected]>
[ Upstream commit a389087ee9f195fcf2f31cd771e9ec5f02c16650 ]
Using a fixed 1s timeout for all commands is a bit problematic.
For some commands it means waiting longer than needed for the timeout to expire, which may not a big issue, but still. For other commands, like for an erase (CMD38) that uses a R1B response, may require longer timeouts than 1s. In these cases, we may end up treating the command as it failed, while it just needed some more time to complete successfully.
Fix the problem by respecting the cmd->busy_timeout, which is provided by the mmc core.
--- drivers/staging/greybus/sdio.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/staging/greybus/sdio.c +7 -3
@@ -411,6 +411,7 @@ static int gb_sdio_command(struct gb_sdio_host *host, struct mmc_command *cmd)struct gb_sdio_command_request request = {0 };struct gb_sdio_command_response response;struct mmc_data *data = host->mrq->data; +unsigned int timeout_ms;u8 cmd_flags;u8 cmd_type;int i;
@@ -469,9 +470,12 @@ static int gb_sdio_command(struct gb_sdio_host *host, struct mmc_command *cmd) request.data_blksz =cpu_to_le16 (data->blksz); } - ret =gb_operation_sync (host->connection,GB_SDIO_TYPE_COMMAND , - &request,sizeof (request), &response, -sizeof (response)); + timeout_ms = cmd->busy_timeout ? cmd->busy_timeout : +GB_OPERATION_TIMEOUT_DEFAULT ; + + ret =gb_operation_sync_timeout (host->connection,GB_SDIO_TYPE_COMMAND , + &request,sizeof (request), &response, +sizeof (response), timeout_ms);if (ret <0 ) goto out;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 231/376 mmc: owl-mmc: Respect the cmd->busy_timeout from the mmc core
In reply to Greg Kroah-HartmanFrom: Ulf Hansson <[email protected]>
[ Upstream commit f37ac1ae3ca93d0995553ad9604a25eadfe9406d ]
For commands that doesn't involve to prepare a data transfer, owl-mmc is using a fixed 30s response timeout. This is a bit problematic.
For some commands it means waiting longer than needed for the completion to expire, which may not a big issue, but still. For other commands, like for an erase (CMD38) that uses a R1B response, may require longer timeouts than 30s. In these cases, we may end up treating the command as it failed, while it just needed some more time to complete successfully.
Fix the problem by respecting the cmd->busy_timeout, which is provided by the mmc core.
--- drivers/mmc/host/owl-mmc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/mmc/host/owl-mmc.c +7 -1
@@ -92,6 +92,8 @@#define OWL_SD_STATE_RC16ER BIT(1)#define OWL_SD_STATE_CRC7ER BIT(0) +#define OWL_CMD_TIMEOUT_MS 30000 +struct owl_mmc_host {struct device *dev;struct reset_control *reset;
@@ -172,6 +174,7 @@ static void owl_mmc_send_cmd(struct owl_mmc_host *owl_host,struct mmc_command *cmd, struct mmc_data *data) { + unsigned long timeout;u32 mode, state, resp[2 ];u32 cmd_rsp_mask =0 ;
@@ -239,7 +242,10 @@ static void owl_mmc_send_cmd(struct owl_mmc_host *owl_host,if (data)return ; -if (!wait_for_completion_timeout (&owl_host->sdc_complete,30 *HZ )) { + timeout =msecs_to_jiffies (cmd->busy_timeout ? cmd->busy_timeout : +OWL_CMD_TIMEOUT_MS ); + +if (!wait_for_completion_timeout (&owl_host->sdc_complete, timeout)) {dev_err (owl_host->dev,"CMD interrupt timeout\n" ); cmd->error = -ETIMEDOUT ;return ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 232/376 mmc: via-sdmmc: Respect the cmd->busy_timeout from the mmc core
In reply to Greg Kroah-HartmanFrom: Ulf Hansson <[email protected]>
[ Upstream commit 966244ccd2919e28f25555a77f204cd1c109cad8 ]
Using a fixed 1s timeout for all commands (and data transfers) is a bit problematic.
For some commands it means waiting longer than needed for the timer to expire, which may not a big issue, but still. For other commands, like for an erase (CMD38) that uses a R1B response, may require longer timeouts than 1s. In these cases, we may end up treating the command as it failed, while it just needed some more time to complete successfully.
Fix the problem by respecting the cmd->busy_timeout, which is provided by the mmc core.
--- drivers/mmc/host/via-sdmmc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/mmc/host/via-sdmmc.c +6 -1
@@ -319,6 +319,8 @@ struct via_crdr_mmc_host {/* some devices need a very long delay for power to stabilize */ #define VIA_CRDR_QUIRK_300MS_PWRDELAY 0x0001 +#define VIA_CMD_TIMEOUT_MS 1000 +static const struct pci_device_id via_ids[] = { {PCI_VENDOR_ID_VIA ,PCI_DEVICE_ID_VIA_9530 ,PCI_ANY_ID ,PCI_ANY_ID ,0 ,0 ,0 ,},
@@ -551,14 +553,17 @@ static void via_sdc_send_command(struct via_crdr_mmc_host *host, {void __iomem *addrbase;struct mmc_data *data; +unsigned int timeout_ms;u32 cmdctrl =0 ;WARN_ON (host->cmd); data = cmd->data; -mod_timer (&host->timer, jiffies +HZ ); host->cmd = cmd; + timeout_ms = cmd->busy_timeout ? cmd->busy_timeout :VIA_CMD_TIMEOUT_MS ; +mod_timer (&host->timer, jiffies +msecs_to_jiffies (timeout_ms)); +/*Command index*/ cmdctrl = cmd->opcode <<8 ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 233/376 mmc: sdhci: add quirks for be to le byte swapping
In reply to Greg Kroah-HartmanFrom: Angelo Dureghello <[email protected]>
[ Upstream commit e93577ecde8f3cbd12a2eaa0522d5c85e0dbdd53 ]
Some controller as the ColdFire eshdc may require an endianness byte swap, because DMA read endianness is not configurable.
Facilitate using the bounce buffer for this by adding ->copy_to_bounce_buffer().
--- drivers/mmc/host/sdhci.c | 10 +++++++--- drivers/mmc/host/sdhci.h | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-)
drivers/mmc/host/sdhci.c +7 -3
@@ -634,9 +634,13 @@ static int sdhci_pre_dma_transfer(struct sdhci_host *host, }if (mmc_get_dma_dir (data) ==DMA_TO_DEVICE ) {/* Copy the data to the bounce buffer */ -sg_copy_to_buffer (data->sg, data->sg_len, - host->bounce_buffer, - length); +if (host->ops->copy_to_bounce_buffer) { + host->ops->copy_to_bounce_buffer (host, + data, length); + }else { +sg_copy_to_buffer (data->sg, data->sg_len, + host->bounce_buffer, length); + } }/* Switch ownership to the DMA */ dma_sync_single_for_device(host->mmc->parent,
drivers/mmc/host/sdhci.h +3 -0
@@ -653,6 +653,9 @@ struct sdhci_ops {void (*voltage_switch)(struct sdhci_host *host);void (*adma_write_desc)(struct sdhci_host *host,void **desc,dma_addr_t addr,int len,unsigned int cmd); +void (*copy_to_bounce_buffer)(struct sdhci_host *host, +struct mmc_data *data, +unsigned int length);void (*request_done)(struct sdhci_host *host,struct mmc_request *mrq); };
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 234/376 ice: fix potential double free in probe unrolling
In reply to Greg Kroah-HartmanFrom: Jacob Keller <[email protected]>
[ Upstream commit bc3a024101ca497bea4c69be4054c32a5c349f1d ]
If ice_init_interrupt_scheme fails, ice_probe will jump to clearing up the interrupts. This can lead to some static analysis tools such as the compiler sanitizers complaining about double free problems.
Since ice_init_interrupt_scheme already unrolls internally on failure, there is no need to call ice_clear_interrupt_scheme when it fails. Add a new unroll label and use that instead.
--- drivers/net/ethernet/intel/ice/ice_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/intel/ice/ice_main.c +2 -1
@@ -3298,7 +3298,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)if (err) {dev_err (dev,"ice_init_interrupt_scheme failed: %d\n" , err); err = -EIO ; - goto err_init_interrupt_unroll; + goto err_init_vsi_unroll; }/* Driver is mostly up */
@@ -3387,6 +3387,7 @@ err_msix_misc_unroll:ice_free_irq_msix_misc (pf); err_init_interrupt_unroll:ice_clear_interrupt_scheme (pf); +err_init_vsi_unroll:devm_kfree (dev, pf->vsi); err_init_pf_unroll:ice_deinit_pf (pf);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 235/376 ixgbe: fix signed-integer-overflow warning
In reply to Greg Kroah-HartmanFrom: Xie XiuQi <[email protected]>
[ Upstream commit 3b70683fc4d68f5d915d9dc7e5ba72c732c7315c ]
ubsan report this warning, fix it by adding a unsigned suffix.
UBSAN: signed-integer-overflow in drivers/net/ethernet/intel/ixgbe/ixgbe_common.c:2246:26 65535 * 65537 cannot be represented in type 'int' CPU: 21 PID: 7 Comm: kworker/u256:0 Not tainted 5.7.0-rc3-debug+ #39 Hardware name: Huawei TaiShan 2280 V2/BC82AMDC, BIOS 2280-V2 03/27/2020 Workqueue: ixgbe ixgbe_service_task [ixgbe] Call trace: dump_backtrace+0x0/0x3f0 show_stack+0x28/0x38 dump_stack+0x154/0x1e4 ubsan_epilogue+0x18/0x60 handle_overflow+0xf8/0x148 __ubsan_handle_mul_overflow+0x34/0x48 ixgbe_fc_enable_generic+0x4d0/0x590 [ixgbe] ixgbe_service_task+0xc20/0x1f78 [ixgbe] process_one_work+0x8f0/0xf18 worker_thread+0x430/0x6d0 kthread+0x218/0x238 ret_from_fork+0x10/0x18
--- drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +1 -1
@@ -2243,7 +2243,7 @@ s32 ixgbe_fc_enable_generic(struct ixgbe_hw *hw) }/* Configure pause time (2 TCs per register) */ - reg = hw->fc.pause_time *0x00010001 ; + reg = hw->fc.pause_time *0x00010001U ;for (i =0 ; i < (MAX_TRAFFIC_CLASS /2 ); i++)IXGBE_WRITE_REG (hw,IXGBE_FCTTV (i), reg);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 236/376 iwlwifi: mvm: fix aux station leak
In reply to Greg Kroah-HartmanFrom: Sharon <[email protected]>
[ Upstream commit f327236df2afc8c3c711e7e070f122c26974f4da ]
When mvm is initialized we alloc aux station with aux queue. We later free the station memory when driver is stopped, but we never free the queue's memory, which casues a leak.
Add a proper de-initialization of the station.
--- .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 5 ++--- drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 18 +++++++++++++----- drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 6 +++--- 3 files changed, 18 insertions(+), 11 deletions(-)
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c +2 -3
@@ -1209,14 +1209,13 @@ void __iwl_mvm_mac_stop(struct iwl_mvm *mvm)*/ flush_work (&mvm->roc_done_wk); +iwl_mvm_rm_aux_sta (mvm); +iwl_mvm_stop_device (mvm);iwl_mvm_async_handlers_purge (mvm);/* async_handlers_list is empty and will stay empty: HW is stopped */ -/* the fw is stopped, the aux sta is dead: clean up driver state */ -iwl_mvm_del_aux_sta (mvm); -/* * Clear IN_HW_RESTART and HW_RESTART_REQUESTED flag when stopping the * hw (as restart_complete() won't be called in this case) and mac80211
drivers/net/wireless/intel/iwlwifi/mvm/sta.c +13 -5
@@ -2080,16 +2080,24 @@ int iwl_mvm_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)return ret; } -void iwl_mvm_dealloc_snif_sta (struct iwl_mvm *mvm) +int iwl_mvm_rm_aux_sta (struct iwl_mvm *mvm) { -iwl_mvm_dealloc_int_sta (mvm, &mvm->snif_sta); -} +int ret; -void iwl_mvm_del_aux_sta (struct iwl_mvm *mvm) -{lockdep_assert_held (&mvm->mutex); +iwl_mvm_disable_txq (mvm,NULL , mvm->aux_queue,IWL_MAX_TID_COUNT ,0 ); + ret =iwl_mvm_rm_sta_common (mvm, mvm->aux_sta.sta_id); +if (ret) +IWL_WARN (mvm,"Failed sending remove station\n" );iwl_mvm_dealloc_int_sta (mvm, &mvm->aux_sta); + +return ret; +} + +void iwl_mvm_dealloc_snif_sta (struct iwl_mvm *mvm) +{ +iwl_mvm_dealloc_int_sta (mvm, &mvm->snif_sta); }/*
drivers/net/wireless/intel/iwlwifi/mvm/sta.h +3 -3
@@ -8,7 +8,7 @@* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2016 Intel Deutschland GmbH -* Copyright(c) 2018 - 2019 Intel Corporation +* Copyright(c) 2018 - 2020 Intel Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as
@@ -31,7 +31,7 @@* Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH * Copyright(c) 2015 - 2016 Intel Deutschland GmbH -* Copyright(c) 2018 - 2019 Intel Corporation +* Copyright(c) 2018 - 2020 Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without
@@ -541,7 +541,7 @@ int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta, int tid, u8 queue, bool start);int iwl_mvm_add_aux_sta (struct iwl_mvm *mvm); -void iwl_mvm_del_aux_sta (struct iwl_mvm *mvm); +int iwl_mvm_rm_aux_sta (struct iwl_mvm *mvm);int iwl_mvm_alloc_bcast_sta (struct iwl_mvm *mvm,struct ieee80211_vif *vif);int iwl_mvm_send_add_bcast_sta (struct iwl_mvm *mvm,struct ieee80211_vif *vif);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 237/376 mmc: sdhci-esdhc-imx: fix the mask for tuning start point
In reply to Greg Kroah-HartmanFrom: Haibo Chen <[email protected]>
[ Upstream commit 1194be8c949b8190b2882ad8335a5d98aa50c735 ]
According the RM, the bit[6~0] of register ESDHC_TUNING_CTRL is TUNING_START_TAP, bit[7] of this register is to disable the command CRC check for standard tuning. So fix it here.
--- drivers/mmc/host/sdhci-esdhc-imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mmc/host/sdhci-esdhc-imx.c +1 -1
@@ -89,7 +89,7 @@#define ESDHC_STD_TUNING_EN (1 << 24)/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ #define ESDHC_TUNING_START_TAP_DEFAULT 0x1 -#define ESDHC_TUNING_START_TAP_MASK 0xff +#define ESDHC_TUNING_START_TAP_MASK 0x7f#define ESDHC_TUNING_STEP_MASK 0x00070000#define ESDHC_TUNING_STEP_SHIFT 16
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 238/376 spi: dw: Return any value retrieved from the dma_transfer callback
In reply to Greg Kroah-HartmanFrom: Serge Semin <[email protected]>
[ Upstream commit f0410bbf7d0fb80149e3b17d11d31f5b5197873e ]
DW APB SSI DMA-part of the driver may need to perform the requested SPI-transfer synchronously. In that case the dma_transfer() callback will return 0 as a marker of the SPI transfer being finished so the SPI core doesn't need to wait and may proceed with the SPI message trasnfers pumping procedure. This will be needed to fix the problem when DMA transactions are finished, but there is still data left in the SPI Tx/Rx FIFOs being sent/received. But for now make dma_transfer to return 1 as the normal dw_spi_transfer_one() method.
--- drivers/spi/spi-dw-mid.c | 2 +- drivers/spi/spi-dw.c | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-)
drivers/spi/spi-dw-mid.c +1 -1
@@ -266,7 +266,7 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, struct spi_transfer *xfer)dma_async_issue_pending (dws->txchan); } -return 0 ; +return 1 ; }static void mid_spi_dma_stop (struct dw_spi *dws)
drivers/spi/spi-dw.c +2 -5
@@ -381,11 +381,8 @@ static int dw_spi_transfer_one(struct spi_controller *master,spi_enable_chip (dws,1 ); -if (dws->dma_mapped) { - ret = dws->dma_ops->dma_transfer (dws, transfer); -if (ret <0 ) -return ret; - } +if (dws->dma_mapped) +return dws->dma_ops->dma_transfer (dws, transfer);if (chip->poll_mode)return poll_transfer (dws);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 239/376 cpuidle: Fix three reference count leaks
In reply to Greg Kroah-HartmanFrom: Qiushi Wu <[email protected]>
[ Upstream commit c343bf1ba5efcbf2266a1fe3baefec9cc82f867f ]
kobject_init_and_add() takes reference even when it fails. If this function returns an error, kobject_put() must be called to properly clean up the memory associated with the object.
Previous commit "b8eb718348b8" fixed a similar problem.
--- drivers/cpuidle/sysfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/cpuidle/sysfs.c +3 -3
@@ -515,7 +515,7 @@ static int cpuidle_add_state_sysfs(struct cpuidle_device *device) ret =kobject_init_and_add (&kobj->kobj, &ktype_state_cpuidle, &kdev->kobj,"state%d" , i);if (ret) { -kfree (kobj); +kobject_put (&kobj->kobj); goto error_state; }cpuidle_add_s2idle_attr_group (kobj);
@@ -646,7 +646,7 @@ static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev) ret =kobject_init_and_add (&kdrv->kobj, &ktype_driver_cpuidle, &kdev->kobj,"driver" );if (ret) { -kfree (kdrv); +kobject_put (&kdrv->kobj);return ret; }
@@ -740,7 +740,7 @@ int cpuidle_add_sysfs(struct cpuidle_device *dev) error =kobject_init_and_add (&kdev->kobj, &ktype_cpuidle, &cpu_dev->kobj,"cpuidle" );if (error) { -kfree (kdev); +kobject_put (&kdev->kobj);return error; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 240/376 spi: spi-fsl-dspi: fix native data copy
In reply to Greg Kroah-HartmanFrom: Angelo Dureghello <[email protected]>
[ Upstream commit 263b81dc6c932c8bc550d5e7bfc178d2b3fc491e ]
ColdFire is a big-endian cpu with a big-endian dspi hw module, so, it uses native access, but memcpy breaks the endianness.
So, if i understand properly, by native copy we would mean be(cpu)->be(dspi) or le(cpu)->le(dspi) accesses, so my fix shouldn't break anything, but i couldn't test it on LS family, so every test is really appreciated.
--- drivers/spi/spi-fsl-dspi.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-)
drivers/spi/spi-fsl-dspi.c +22 -2
@@ -246,13 +246,33 @@ struct fsl_dspi {static void dspi_native_host_to_dev (struct fsl_dspi *dspi,u32 *txdata) { -memcpy (txdata, dspi->tx, dspi->oper_word_size); +switch (dspi->oper_word_size) { +case 1 : + *txdata = *(u8 *)dspi->tx; +break ; +case 2 : + *txdata = *(u16 *)dspi->tx; +break ; +case 4 : + *txdata = *(u32 *)dspi->tx; +break ; + } dspi->tx += dspi->oper_word_size; }static void dspi_native_dev_to_host (struct fsl_dspi *dspi,u32 rxdata) { -memcpy (dspi->rx, &rxdata, dspi->oper_word_size); +switch (dspi->oper_word_size) { +case 1 : + *(u8 *)dspi->rx = rxdata; +break ; +case 2 : + *(u16 *)dspi->rx = rxdata; +break ; +case 4 : + *(u32 *)dspi->rx = rxdata; +break ; + } dspi->rx += dspi->oper_word_size; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 241/376 io_uring: fix overflowed reqs cancellation
In reply to Greg Kroah-HartmanFrom: Pavel Begunkov <[email protected]>
[ Upstream commit 7b53d59859bc932b37895d2d37388e7fa29af7a5 ]
Overflowed requests in io_uring_cancel_files() should be shed only of inflight and overflowed refs. All other left references are owned by someone else.
If refcount_sub_and_test() fails, it will go further and put put extra ref, don't do that. Also, don't need to do io_wq_cancel_work() for overflowed reqs, they will be let go shortly anyway.
--- fs/io_uring.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/io_uring.c +3 -2
@@ -7477,10 +7477,11 @@ static void io_uring_cancel_files(struct io_ring_ctx *ctx,finish_wait (&ctx->inflight_wait, &wait);continue ; } + }else { +io_wq_cancel_work (ctx->io_wq, &cancel_req->work); +io_put_req (cancel_req); } -io_wq_cancel_work (ctx->io_wq, &cancel_req->work); -io_put_req (cancel_req);schedule ();finish_wait (&ctx->inflight_wait, &wait); }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 242/376 platform/x86: hp-wmi: Convert simple_strtoul() to kstrtou32()
In reply to Greg Kroah-HartmanFrom: Andy Shevchenko <[email protected]>
[ Upstream commit 5cdc45ed3948042f0d73c6fec5ee9b59e637d0d2 ]
First of all, unsigned long can overflow u32 value on 64-bit machine. Second, simple_strtoul() doesn't check for overflow in the input.
Convert simple_strtoul() to kstrtou32() to eliminate above issues.
--- drivers/platform/x86/hp-wmi.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/platform/x86/hp-wmi.c +8 -2
@@ -461,8 +461,14 @@ static ssize_t postcode_show(struct device *dev, struct device_attribute *attr,static ssize_t als_store (struct device *dev,struct device_attribute *attr,const char *buf,size_t count) { -u32 tmp =simple_strtoul (buf,NULL ,10 ); -int ret =hp_wmi_perform_query (HPWMI_ALS_QUERY ,HPWMI_WRITE , &tmp, +u32 tmp; +int ret; + + ret =kstrtou32 (buf,10 , &tmp); +if (ret) +return ret; + + ret =hp_wmi_perform_query (HPWMI_ALS_QUERY ,HPWMI_WRITE , &tmp,sizeof (tmp),sizeof (tmp));if (ret)return ret <0 ? ret : -EINVAL ;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 243/376 ice: Fix inability to set channels when down
In reply to Greg Kroah-HartmanFrom: Jesse Brandeburg <[email protected]>
[ Upstream commit 765dd7a1827c687b782e6ab3dd6daf4d13a4780f ]
Currently the driver prevents a user from doing
modprobe ice
ethtool -L eth0 combined 5
ip link set eth0 up
The ethtool command fails, because the driver is checking to see if the interface is down before allowing the get_channels to proceed (even for a set_channels).
Remove this check and allow the user to configure the interface before bringing it up, which is a much better usability case.
--- drivers/net/ethernet/intel/ice/ice_ethtool.c | 4 ---- 1 file changed, 4 deletions(-)
drivers/net/ethernet/intel/ice/ice_ethtool.c +0 -4
@@ -3171,10 +3171,6 @@ ice_get_channels(struct net_device *dev, struct ethtool_channels *ch)struct ice_vsi *vsi = np->vsi;struct ice_pf *pf = vsi->back; -/* check to see if VSI is active */ -if (test_bit (__ICE_DOWN, vsi->state)) -return ; -/* report maximum channels */ ch->max_rx =ice_get_max_rxq (pf); ch->max_tx =ice_get_max_txq (pf);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 244/376 platform/x86: intel-hid: Add a quirk to support HP Spectre X2 (2015)
In reply to Greg Kroah-HartmanFrom: Nickolai Kozachenko <[email protected]>
[ Upstream commit 8fe63eb757ac6e661a384cc760792080bdc738dc ]
HEBC method reports capabilities of 5 button array but HP Spectre X2 (2015) does not have this control method (the same was for Wacom MobileStudio Pro). Expand previous DMI quirk by Alex Hung to also enable 5 button array for this system.
--- drivers/platform/x86/intel-hid.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/platform/x86/intel-hid.c +7 -0
@@ -79,6 +79,13 @@ static const struct dmi_system_id button_array_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Wacom MobileStudio Pro 16"), }, }, + { + .ident = "HP Spectre x2 (2015)", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "HP"), + DMI_MATCH(DMI_PRODUCT_NAME, "HP Spectre x2 Detachable"), + }, + }, { } };
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 245/376 platform/x86: intel-vbtn: Only blacklist SW_TABLET_MODE on the 9 / "Laptop" chasis-type
In reply to Greg Kroah-HartmanFrom: Hans de Goede <[email protected]>
[ Upstream commit cfae58ed681c5fe0185db843013ecc71cd265ebf ]
The HP Stream x360 11-p000nd no longer report SW_TABLET_MODE state / events with recent kernels. This model reports a chassis-type of 10 / "Notebook" which is not on the recently introduced chassis-type whitelist
Commit de9647efeaa9 ("platform/x86: intel-vbtn: Only activate tablet mode switch on 2-in-1's") added a chassis-type whitelist and only listed 31 / "Convertible" as being capable of generating valid SW_TABLET_MOD events.
Commit 1fac39fd0316 ("platform/x86: intel-vbtn: Also handle tablet-mode switch on "Detachable" and "Portable" chassis-types") extended the whitelist with chassis-types 8 / "Portable" and 32 / "Detachable".
And now we need to exten the whitelist again with 10 / "Notebook"...
The issue original fixed by the whitelist is really a ACPI DSDT bug on the Dell XPS 9360 where it has a VGBS which reports it is in tablet mode even though it is not a 2-in-1 at all, but a regular laptop.
So since this is a workaround for a DSDT issue on that specific model, instead of extending the whitelist over and over again, lets switch to a blacklist and only blacklist the chassis-type of the model for which the chassis-type check was added.
Note this also fixes the current version of the code no longer checking if dmi_get_system_info(DMI_CHASSIS_TYPE) returns NULL.
--- drivers/platform/x86/intel-vbtn.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-)
drivers/platform/x86/intel-vbtn.c +8 -11
@@ -158,21 +158,18 @@ static void detect_tablet_mode(struct platform_device *device)static bool intel_vbtn_has_switches (acpi_handle handle) {const char *chassis_type =dmi_get_system_info (DMI_CHASSIS_TYPE ); -unsigned long chassis_type_int;unsigned long long vgbs;acpi_status status; -if (kstrtoul (chassis_type,10 , &chassis_type_int)) -return false; - -switch (chassis_type_int) { -case 8 :/* Portable */ -case 31 :/* Convertible */ -case 32 :/* Detachable */ -break ; -default : +/* +* Some normal laptops have a VGBS method despite being non-convertible +* and their VGBS method always returns 0, causing detect_tablet_mode() +* to report SW_TABLET_MODE=1 to userspace, which causes issues. +* These laptops have a DMI chassis_type of 9 ("Laptop"), do not report +* switches on any devices with a DMI chassis_type of 9. +*/ +if (chassis_type &&strcmp (chassis_type,"9" ) ==0 )return false; - } status =acpi_evaluate_integer (handle,"VGBS" ,NULL , &vgbs);return ACPI_SUCCESS (status);
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 246/376 platform/x86: asus_wmi: Reserve more space for struct bias_args
In reply to Greg Kroah-HartmanFrom: Chris Chiu <[email protected]>
[ Upstream commit 7b91f1565fbfbe5a162d91f8a1f6c5580c2fc1d0 ]
On the ASUS laptop UX325JA/UX425JA, most of the media keys are not
working due to the ASUS WMI driver fails to be loaded. The ACPI error
as follows leads to the failure of asus_wmi_evaluate_method.
ACPI BIOS Error (bug): AE_AML_BUFFER_LIMIT, Field [IIA3] at bit offset/length 96/32 exceeds size of target Buffer (96 bits) (20200326/dsopcode-203) No Local Variables are initialized for Method [WMNB]
ACPI Error: Aborting method \_SB.ATKD.WMNB due to previous error (AE_AML_BUFFER_LIMIT) (20200326/psparse-531)
The DSDT for the WMNB part shows that 5 DWORD required for local variables and the 3rd variable IIA3 hit the buffer limit.
Method (WMNB, 3, Serialized)
{ ..
CreateDWordField (Arg2, Zero, IIA0)
CreateDWordField (Arg2, 0x04, IIA1)
CreateDWordField (Arg2, 0x08, IIA2)
CreateDWordField (Arg2, 0x0C, IIA3)
CreateDWordField (Arg2, 0x10, IIA4)
Local0 = (Arg1 & 0xFFFFFFFF)
If ((Local0 == 0x54494E49)) ..
}
The limitation is determined by the input acpi_buffer size passed to the wmi_evaluate_method. Since the struct bios_args is the data structure used as input buffer by default for all ASUS WMI calls, the size needs to be expanded to fix the problem.
--- drivers/platform/x86/asus-wmi.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/platform/x86/asus-wmi.c +2 -0
@@ -116,6 +116,8 @@ struct bios_args {u32 arg0;u32 arg1;u32 arg2;/* At least TUF Gaming series uses 3 dword input buffer. */ +u32 arg4; +u32 arg5; } __packed;/*
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 247/376 libbpf: Fix perf_buffer__free() API for sparse allocs
In reply to Greg Kroah-HartmanFrom: Eelco Chaudron <[email protected]>
[ Upstream commit 601b05ca6edb0422bf6ce313fbfd55ec7bbbc0fd ]
In case the cpu_bufs are sparsely allocated they are not all free'ed. These changes will fix this.
--- tools/lib/bpf/libbpf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
tools/lib/bpf/libbpf.c +4 -1
@@ -7809,9 +7809,12 @@ void perf_buffer__free(struct perf_buffer *pb)if (!pb)return ;if (pb->cpu_bufs) { -for (i =0 ; i < pb->cpu_cnt && pb->cpu_bufs[i]; i++) { +for (i =0 ; i < pb->cpu_cnt; i++) {struct perf_cpu_buf *cpu_buf = pb->cpu_bufs[i]; +if (!cpu_buf) +continue ; +bpf_map_delete_elem (pb->map_fd, &cpu_buf->map_key);perf_buffer__free_cpu_buf (pb, cpu_buf); }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 248/376 bpf: Fix map permissions check
In reply to Greg Kroah-HartmanFrom: Anton Protopopov <[email protected]>
[ Upstream commit 1ea0f9120c8ce105ca181b070561df5cbd6bc049 ]
The map_lookup_and_delete_elem() function should check for both FMODE_CAN_WRITE and FMODE_CAN_READ permissions because it returns a map element to user space.
--- kernel/bpf/syscall.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/bpf/syscall.c +2 -1
@@ -1468,7 +1468,8 @@ static int map_lookup_and_delete_elem(union bpf_attr *attr) map =__bpf_map_get (f);if (IS_ERR (map))return PTR_ERR (map); -if (!(map_get_sys_perms (map, f) &FMODE_CAN_WRITE )) { +if (!(map_get_sys_perms (map, f) &FMODE_CAN_READ ) || + !(map_get_sys_perms (map, f) &FMODE_CAN_WRITE )) { err = -EPERM ; goto err_put; }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 249/376 bpf: Refactor sockmap redirect code so its easy to reuse
In reply to Greg Kroah-HartmanFrom: John Fastabend <[email protected]>
[ Upstream commit ca2f5f21dbbd5e3a00cd3e97f728aa2ca0b2e011 ]
We will need this block of code called from tls context shortly lets refactor the redirect logic so its easy to use. This also cleans up the switch stmt so we have fewer fallthrough cases.
No logic changes are intended.
--- net/core/skmsg.c | 55 ++++++++++++++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 21 deletions(-)
net/core/skmsg.c +34 -21
@@ -682,13 +682,43 @@ static struct sk_psock *sk_psock_from_strp(struct strparser *strp) return container_of(parser, struct sk_psock, parser); } -static void sk_psock_verdict_apply (struct sk_psock *psock, -struct sk_buff *skb,int verdict) +static void sk_psock_skb_redirect (struct sk_psock *psock,struct sk_buff *skb) {struct sk_psock *psock_other;struct sock *sk_other;bool ingress; + sk_other =tcp_skb_bpf_redirect_fetch (skb); +if (unlikely (!sk_other)) { +kfree_skb (skb); +return ; + } + psock_other =sk_psock (sk_other); +if (!psock_other ||sock_flag (sk_other,SOCK_DEAD ) || + !sk_psock_test_state (psock_other,SK_PSOCK_TX_ENABLED )) { +kfree_skb (skb); +return ; + } + + ingress =tcp_skb_bpf_ingress (skb); +if ((!ingress &&sock_writeable (sk_other)) || + (ingress && +atomic_read (&sk_other->sk_rmem_alloc) <= + sk_other->sk_rcvbuf)) { +if (!ingress) +skb_set_owner_w (skb, sk_other); +skb_queue_tail (&psock_other->ingress_skb, skb); +schedule_work (&psock_other->work); + }else { +kfree_skb (skb); + } +} + +static void sk_psock_verdict_apply (struct sk_psock *psock, +struct sk_buff *skb,int verdict) +{ +struct sock *sk_other; +switch (verdict) {case __SK_PASS: sk_other = psock->sk;
@@ -707,25 +737,8 @@ static void sk_psock_verdict_apply(struct sk_psock *psock, } goto out_free;case __SK_REDIRECT: - sk_other =tcp_skb_bpf_redirect_fetch (skb); -if (unlikely (!sk_other)) - goto out_free; - psock_other =sk_psock (sk_other); -if (!psock_other ||sock_flag (sk_other,SOCK_DEAD ) || - !sk_psock_test_state (psock_other,SK_PSOCK_TX_ENABLED )) - goto out_free; - ingress =tcp_skb_bpf_ingress (skb); -if ((!ingress &&sock_writeable (sk_other)) || - (ingress && -atomic_read (&sk_other->sk_rmem_alloc) <= - sk_other->sk_rcvbuf)) { -if (!ingress) -skb_set_owner_w (skb, sk_other); -skb_queue_tail (&psock_other->ingress_skb, skb); -schedule_work (&psock_other->work); -break ; - } -/* fall-through */ +sk_psock_skb_redirect (psock, skb); +break ;case __SK_DROP:/* fall-through */ default :
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 250/376 bpf: Fix running sk_skb program types with ktls
In reply to Greg Kroah-HartmanFrom: John Fastabend <[email protected]>
[ Upstream commit e91de6afa81c10e9f855c5695eb9a53168d96b73 ]
KTLS uses a stream parser to collect TLS messages and send them to the upper layer tls receive handler. This ensures the tls receiver has a full TLS header to parse when it is run. However, when a socket has BPF_SK_SKB_STREAM_VERDICT program attached before KTLS is enabled we end up with two stream parsers running on the same socket.
The result is both try to run on the same socket. First the KTLS stream parser runs and calls read_sock() which will tcp_read_sock which in turn calls tcp_rcv_skb(). This dequeues the skb from the sk_receive_queue. When this is done KTLS code then data_ready() callback which because we stacked KTLS on top of the bpf stream verdict program has been replaced with sk_psock_start_strp(). This will in turn kick the stream parser again and eventually do the same thing KTLS did above calling into tcp_rcv_skb() and dequeuing a skb from the sk_receive_queue.
At this point the data stream is broke. Part of the stream was handled by the KTLS side some other bytes may have been handled by the BPF side. Generally this results in either missing data or more likely a "Bad Message" complaint from the kTLS receive handler as the BPF program steals some bytes meant to be in a TLS header and/or the TLS header length is no longer correct.
We've already broke the idealized model where we can stack ULPs in any order with generic callbacks on the TX side to handle this. So in this patch we do the same thing but for RX side. We add a sk_psock_strp_enabled() helper so TLS can learn a BPF verdict program is running and add a tls_sw_has_ctx_rx() helper so BPF side can learn there is a TLS ULP on the socket.
Then on BPF side we omit calling our stream parser to avoid breaking the data stream for the KTLS receiver. Then on the KTLS side we call BPF_SK_SKB_STREAM_VERDICT once the KTLS receiver is done with the packet but before it posts the msg to userspace. This gives us symmetry between the TX and RX halfs and IMO makes it usable again. On the TX side we process packets in this order BPF -> TLS -> TCP and on the receive side in the reverse order TCP -> TLS -> BPF.
Discovered while testing OpenSSL 3.0 Alpha2.0 release.
--- include/linux/skmsg.h | 8 ++++++++ include/net/tls.h | 9 +++++++++ net/core/skmsg.c | 43 ++++++++++++++++++++++++++++++++++++++++--- net/tls/tls_sw.c | 20 ++++++++++++++++++-- 4 files changed, 75 insertions(+), 5 deletions(-)
include/linux/skmsg.h +8 -0
@@ -437,4 +437,12 @@ static inline void psock_progs_drop(struct sk_psock_progs *progs) psock_set_prog(&progs->skb_verdict, NULL); } +int sk_psock_tls_strp_read (struct sk_psock *psock,struct sk_buff *skb); + +static inline bool sk_psock_strp_enabled (struct sk_psock *psock) +{ +if (!psock) +return false; +return psock->parser.enabled; +}#endif /* _LINUX_SKMSG_H */
include/net/tls.h +9 -0
@@ -571,6 +571,15 @@ static inline bool tls_sw_has_ctx_tx(const struct sock *sk)return !!tls_sw_ctx_tx (ctx); } +static inline bool tls_sw_has_ctx_rx (const struct sock *sk) +{ +struct tls_context *ctx =tls_get_ctx (sk); + +if (!ctx) +return false; +return !!tls_sw_ctx_rx (ctx); +} +void tls_sw_write_space (struct sock *sk,struct tls_context *ctx);void tls_device_write_space (struct sock *sk,struct tls_context *ctx);
net/core/skmsg.c +40 -3
61 lines not on this page · raw message
net/tls/tls_sw.c +18 -2
@@ -1742,6 +1742,7 @@ int tls_sw_recvmsg(struct sock *sk,long timeo;bool is_kvec =iov_iter_is_kvec (&msg->msg_iter);bool is_peek = flags &MSG_PEEK ; +bool bpf_strp_enabled;int num_async =0 ;int pending;
@@ -1752,6 +1753,7 @@ int tls_sw_recvmsg(struct sock *sk, psock =sk_psock_get (sk);lock_sock (sk); + bpf_strp_enabled =sk_psock_strp_enabled (psock);/* Process pending decrypted records. It must be non-zero-copy */ err = process_rx_list(ctx, msg, &control, &cmsg, 0, len, false,
@@ -1805,11 +1807,12 @@ int tls_sw_recvmsg(struct sock *sk,if (to_decrypt <= len && !is_kvec && !is_peek && ctx->control ==TLS_RECORD_TYPE_DATA && - prot->version !=TLS_1_3_VERSION ) + prot->version !=TLS_1_3_VERSION && + !bpf_strp_enabled) zc = true;/* Do not use async mode if record is non-data */ -if (ctx->control ==TLS_RECORD_TYPE_DATA ) +if (ctx->control ==TLS_RECORD_TYPE_DATA && !bpf_strp_enabled) async_capable = ctx->async_capable;else async_capable = false;
@@ -1859,6 +1862,19 @@ int tls_sw_recvmsg(struct sock *sk, goto pick_next_record;if (!zc) { +if (bpf_strp_enabled) { + err =sk_psock_tls_strp_read (psock, skb); +if (err != __SK_PASS) { + rxm->offset = rxm->offset + rxm->full_len; + rxm->full_len =0 ; +if (err == __SK_DROP) +consume_skb (skb); + ctx->recv_pkt =NULL ; +__strp_unpause (&ctx->strp); +continue ; + } + } +if (rxm->full_len > len) { retain_skb = true; chunk = len;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 251/376 selftests/bpf, flow_dissector: Close TAP device FD after the test
In reply to Greg Kroah-HartmanFrom: Jakub Sitnicki <[email protected]>
[ Upstream commit b8215dce7dfd817ca38807f55165bf502146cd68 ]
test_flow_dissector leaves a TAP device after it's finished, potentially interfering with other tests that will run after it. Fix it by closing the TAP descriptor on cleanup.
--- tools/testing/selftests/bpf/prog_tests/flow_dissector.c | 1 + 1 file changed, 1 insertion(+)
tools/testing/selftests/bpf/prog_tests/flow_dissector.c +1 -0
@@ -523,6 +523,7 @@ void test_flow_dissector(void)CHECK_ATTR (err, tests[i].name,"bpf_map_delete_elem %d\n" , err); } +close (tap_fd);bpf_prog_detach (prog_fd,BPF_FLOW_DISSECTOR );bpf_object__close (obj); }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 252/376 bpf: Fix up bpf_skb_adjust_room helpers skb csum setting
In reply to Greg Kroah-HartmanFrom: Daniel Borkmann <[email protected]>
[ Upstream commit 836e66c218f355ec01ba57671c85abf32961dcea ]
Lorenz recently reported:
In our TC classifier cls_redirect [0], we use the following sequence of helper calls to decapsulate a GUE (basically IP + UDP + custom header) encapsulated packet:
bpf_skb_adjust_room(skb, -encap_len, BPF_ADJ_ROOM_MAC, BPF_F_ADJ_ROOM_FIXED_GSO) bpf_redirect(skb->ifindex, BPF_F_INGRESS)
It seems like some checksums of the inner headers are not validated in this case. For example, a TCP SYN packet with invalid TCP checksum is still accepted by the network stack and elicits a SYN ACK. [...]
That is, we receive the following packet from the driver:
| ETH | IP | UDP | GUE | IP | TCP |
skb->ip_summed == CHECKSUM_UNNECESSARY
ip_summed is CHECKSUM_UNNECESSARY because our NICs do rx checksum offloading. On this packet we run skb_adjust_room_mac(-encap_len), and get the following:
| ETH | IP | TCP |
skb->ip_summed == CHECKSUM_UNNECESSARY
Note that ip_summed is still CHECKSUM_UNNECESSARY. After bpf_redirect()'ing into the ingress, we end up in tcp_v4_rcv(). There, skb_checksum_init() is turned into a no-op due to CHECKSUM_UNNECESSARY.
The bpf_skb_adjust_room() helper is not aware of protocol specifics. Internally, it handles the CHECKSUM_COMPLETE case via skb_postpull_rcsum(), but that does not cover CHECKSUM_UNNECESSARY. In this case skb->csum_level of the original skb prior to bpf_skb_adjust_room() call was 0, that is, covering UDP. Right now there is no way to adjust the skb->csum_level. NICs that have checksum offload disabled (CHECKSUM_NONE) or that support CHECKSUM_COMPLETE are not affected.
Use a safe default for CHECKSUM_UNNECESSARY by resetting to CHECKSUM_NONE and add a flag to the helper called BPF_F_ADJ_ROOM_NO_CSUM_RESET that allows users from opting out. Opting out is useful for the case where we don't remove/add full protocol headers, or for the case where a user wants to adjust the csum level manually e.g. through bpf_csum_level() helper that is added in subsequent patch.
The bpf_skb_proto_{4_to_6,6_to_4}() for NAT64/46 translation from the BPF bpf_skb_change_proto() helper uses bpf_skb_net_hdr_{push,pop}() pair internally as well but doesn't change layers, only transitions between v4 to v6 and vice versa, therefore no adoption is required there.
[0] https://lore.kernel.org/bpf/[email protected]/
--- include/linux/skbuff.h | 8 ++++++++ include/uapi/linux/bpf.h | 8 ++++++++ net/core/filter.c | 8 ++++++-- tools/include/uapi/linux/bpf.h | 8 ++++++++ 4 files changed, 30 insertions(+), 2 deletions(-)
include/linux/skbuff.h +8 -0
@@ -3945,6 +3945,14 @@ static inline void __skb_incr_checksum_unnecessary(struct sk_buff *skb) } } +static inline void __skb_reset_checksum_unnecessary (struct sk_buff *skb) +{ +if (skb->ip_summed ==CHECKSUM_UNNECESSARY ) { + skb->ip_summed =CHECKSUM_NONE ; + skb->csum_level =0 ; + } +} +/* Check if we need to perform checksum complete validation. * * Returns true if checksum complete is needed, false otherwise
include/uapi/linux/bpf.h +8 -0
@@ -1589,6 +1589,13 @@ union bpf_attr {* Grow or shrink the room for data in the packet associated to * *skb* by *len_diff*, and according to the selected *mode*. * +* By default, the helper will reset any offloaded checksum +* indicator of the skb to CHECKSUM_NONE. This can be avoided +* by the following flag: +* +* * **BPF_F_ADJ_ROOM_NO_CSUM_RESET**: Do not reset offloaded +* checksum data of the skb to CHECKSUM_NONE. +* * There are two supported modes at this time: * * * **BPF_ADJ_ROOM_MAC**: Adjust room at the mac layer
@@ -3235,6 +3242,7 @@ enum {BPF_F_ADJ_ROOM_ENCAP_L3_IPV6 = (1ULL <<2 ),BPF_F_ADJ_ROOM_ENCAP_L4_GRE = (1ULL <<3 ),BPF_F_ADJ_ROOM_ENCAP_L4_UDP = (1ULL <<4 ), + BPF_F_ADJ_ROOM_NO_CSUM_RESET = (1ULL << 5), }; enum {
net/core/filter.c +6 -2
@@ -3124,7 +3124,8 @@ static int bpf_skb_net_shrink(struct sk_buff *skb, u32 off, u32 len_diff, {int ret; -if (flags & ~BPF_F_ADJ_ROOM_FIXED_GSO ) +if (unlikely (flags & ~(BPF_F_ADJ_ROOM_FIXED_GSO | +BPF_F_ADJ_ROOM_NO_CSUM_RESET )))return -EINVAL ;if (skb_is_gso (skb) && !skb_is_gso_tcp (skb)) {
@@ -3174,7 +3175,8 @@ BPF_CALL_4(bpf_skb_adjust_room, struct sk_buff *, skb, s32, len_diff,u32 off;int ret; -if (unlikely (flags & ~BPF_F_ADJ_ROOM_MASK )) +if (unlikely (flags & ~(BPF_F_ADJ_ROOM_MASK | +BPF_F_ADJ_ROOM_NO_CSUM_RESET )))return -EINVAL ;if (unlikely (len_diff_abs >0xfffU ))return -EFAULT ;
@@ -3202,6 +3204,8 @@ BPF_CALL_4(bpf_skb_adjust_room, struct sk_buff *, skb, s32, len_diff, ret = shrink ?bpf_skb_net_shrink (skb, off, len_diff_abs, flags) :bpf_skb_net_grow (skb, off, len_diff_abs, flags); +if (!ret && !(flags &BPF_F_ADJ_ROOM_NO_CSUM_RESET )) +__skb_reset_checksum_unnecessary (skb);bpf_compute_data_pointers (skb);return ret;
tools/include/uapi/linux/bpf.h +8 -0
@@ -1589,6 +1589,13 @@ union bpf_attr {* Grow or shrink the room for data in the packet associated to * *skb* by *len_diff*, and according to the selected *mode*. * +* By default, the helper will reset any offloaded checksum +* indicator of the skb to CHECKSUM_NONE. This can be avoided +* by the following flag: +* +* * **BPF_F_ADJ_ROOM_NO_CSUM_RESET**: Do not reset offloaded +* checksum data of the skb to CHECKSUM_NONE. +* * There are two supported modes at this time: * * * **BPF_ADJ_ROOM_MAC**: Adjust room at the mac layer
@@ -3235,6 +3242,7 @@ enum {BPF_F_ADJ_ROOM_ENCAP_L3_IPV6 = (1ULL <<2 ),BPF_F_ADJ_ROOM_ENCAP_L4_GRE = (1ULL <<3 ),BPF_F_ADJ_ROOM_ENCAP_L4_UDP = (1ULL <<4 ), + BPF_F_ADJ_ROOM_NO_CSUM_RESET = (1ULL << 5), }; enum {
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 253/376 s390/bpf: Maintain 8-byte stack alignment
In reply to Greg Kroah-HartmanFrom: Ilya Leoshkevich <[email protected]>
[ Upstream commit effe5be17706167ee968fa28afe40dec9c6f71db ]
Certain kernel functions (e.g. get_vtimer/set_vtimer) cause kernel panic when the stack is not 8-byte aligned. Currently JITed BPF programs may trigger this by allocating stack frames with non-rounded sizes and then being interrupted. Fix by using rounded fp->aux->stack_depth.
--- arch/s390/net/bpf_jit_comp.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)
arch/s390/net/bpf_jit_comp.c +10 -9
@@ -594,7 +594,7 @@ static void bpf_jit_epilogue(struct bpf_jit *jit, u32 stack_depth)* stack space for the large switch statement. */ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, -int i,bool extra_pass) +int i,bool extra_pass,u32 stack_depth) {struct bpf_insn *insn = &fp->insnsi[i];u32 dst_reg = insn->dst_reg;
@@ -1207,7 +1207,7 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,*/ if (jit->seen &SEEN_STACK ) - off =STK_OFF_TCCNT +STK_OFF + fp->aux->stack_depth; + off =STK_OFF_TCCNT +STK_OFF + stack_depth;else off =STK_OFF_TCCNT ;/* lhi %w0,1 */
@@ -1249,7 +1249,7 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,/* * Restore registers before calling function */ -save_restore_regs (jit,REGS_RESTORE , fp->aux->stack_depth); +save_restore_regs (jit,REGS_RESTORE , stack_depth);/* * goto *(prog->bpf_func + tail_call_start);
@@ -1519,7 +1519,7 @@ static int bpf_set_addr(struct bpf_jit *jit, int i)* Compile eBPF program into s390x code */ static int bpf_jit_prog (struct bpf_jit *jit,struct bpf_prog *fp, -bool extra_pass) +bool extra_pass,u32 stack_depth) {int i, insn_count, lit32_size, lit64_size;
@@ -1527,18 +1527,18 @@ static int bpf_jit_prog(struct bpf_jit *jit, struct bpf_prog *fp, jit->lit64 = jit->lit64_start; jit->prg =0 ; -bpf_jit_prologue (jit, fp->aux->stack_depth); +bpf_jit_prologue (jit, stack_depth);if (bpf_set_addr (jit,0 ) <0 )return -1 ;for (i =0 ; i < fp->len; i += insn_count) { - insn_count =bpf_jit_insn (jit, fp, i, extra_pass); + insn_count =bpf_jit_insn (jit, fp, i, extra_pass, stack_depth);if (insn_count <0 )return -1 ;/* Next instruction address */ if (bpf_set_addr (jit, i + insn_count) <0 )return -1 ; } -bpf_jit_epilogue (jit, fp->aux->stack_depth); +bpf_jit_epilogue (jit, stack_depth); lit32_size = jit->lit32 - jit->lit32_start; lit64_size = jit->lit64 - jit->lit64_start;
@@ -1569,6 +1569,7 @@ struct s390_jit_data {*/ struct bpf_prog *bpf_int_jit_compile (struct bpf_prog *fp) { +u32 stack_depth =round_up (fp->aux->stack_depth,8 );struct bpf_prog *tmp, *orig_fp = fp;struct bpf_binary_header *header;struct s390_jit_data *jit_data;
@@ -1621,7 +1622,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp)* - 3: Calculate program size and addrs arrray */ for (pass =1 ; pass <=3 ; pass++) { -if (bpf_jit_prog (&jit, fp, extra_pass)) { +if (bpf_jit_prog (&jit, fp, extra_pass, stack_depth)) { fp = orig_fp; goto free_addrs; }
@@ -1635,7 +1636,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) goto free_addrs; } skip_init_ctx: -if (bpf_jit_prog (&jit, fp, extra_pass)) { +if (bpf_jit_prog (&jit, fp, extra_pass, stack_depth)) {bpf_jit_binary_free (header); fp = orig_fp; goto free_addrs;
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 254/376 kasan: stop tests being eliminated as dead code with FORTIFY_SOURCE
In reply to Greg Kroah-HartmanFrom: Daniel Axtens <[email protected]>
[ Upstream commit adb72ae1915db28f934e9e02c18bfcea2f3ed3b7 ]
Patch series "Fix some incompatibilites between KASAN and FORTIFY_SOURCE", v4.
3 KASAN self-tests fail on a kernel with both KASAN and FORTIFY_SOURCE:
memchr, memcmp and strlen.
When FORTIFY_SOURCE is on, a number of functions are replaced with fortified versions, which attempt to check the sizes of the operands. However, these functions often directly invoke __builtin_foo() once they have performed the fortify check. The compiler can detect that the results of these functions are not used, and knows that they have no other side effects, and so can eliminate them as dead code.
Why are only memchr, memcmp and strlen affected?
================================================
Of string and string-like functions, kasan_test tests:
* strchr -> not affected, no fortified version * strrchr -> likewise * strcmp -> likewise * strncmp -> likewise
* strnlen -> not affected, the fortify source implementation calls the underlying strnlen implementation which is instrumented, not a builtin
* strlen -> affected, the fortify souce implementation calls a __builtin version which the compiler can determine is dead.
* memchr -> likewise * memcmp -> likewise
* memset -> not affected, the compiler knows that memset writes to its
first argument and therefore is not dead.
Why does this not affect the functions normally?
================================================
In string.h, these functions are not marked as __pure, so the compiler cannot know that they do not have side effects. If relevant functions are marked as __pure in string.h, we see the following warnings and the functions are elided:
lib/test_kasan.c: In function `kasan_memchr':lib/test_kasan.c:606:2: warning: statement with no effect [-Wunused-value]
memchr(ptr, '1', size + 1);
^~~~~~~~~~~~~~~~~~~~~~~~~~lib/test_kasan.c: In function `kasan_memcmp':lib/test_kasan.c:622:2: warning: statement with no effect [-Wunused-value]
memcmp(ptr, arr, size+1);
^~~~~~~~~~~~~~~~~~~~~~~~lib/test_kasan.c: In function `kasan_strings':lib/test_kasan.c:645:2: warning: statement with no effect [-Wunused-value]
strchr(ptr, '1');
^~~~~~~~~~~~~~~~
...
This annotation would make sense to add and could be added at any point, so the behaviour of test_kasan.c should change.
The fix
=======
Make all the functions that are pure write their results to a global, which makes them live. The strlen and memchr tests now pass.
The memcmp test still fails to trigger, which is addressed in the next patch.
--- lib/test_kasan.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-)
lib/test_kasan.c +19 -10
@@ -23,6 +23,14 @@#include <asm/page.h> +/* +* We assign some test results to these globals to make sure the tests +* are not eliminated as dead code. +*/ + +int kasan_int_result; +void *kasan_ptr_result; +/* * Note: test functions are marked noinline so that their names appear in * reports.
@@ -622,7 +630,7 @@ static noinline void __init kasan_memchr(void)if (!ptr)return ; -memchr (ptr,'1' , size +1 ); + kasan_ptr_result =memchr (ptr,'1' , size +1 );kfree (ptr); }
@@ -638,7 +646,7 @@ static noinline void __init kasan_memcmp(void)return ;memset (arr,0 ,sizeof (arr)); -memcmp (ptr, arr, size+1 ); + kasan_int_result =memcmp (ptr, arr, size +1 );kfree (ptr); }
@@ -661,22 +669,22 @@ static noinline void __init kasan_strings(void)* will likely point to zeroed byte. */ ptr +=16 ; -strchr (ptr,'1' ); + kasan_ptr_result =strchr (ptr,'1' );pr_info ("use-after-free in strrchr\n" ); -strrchr (ptr,'1' ); + kasan_ptr_result =strrchr (ptr,'1' );pr_info ("use-after-free in strcmp\n" ); -strcmp (ptr,"2" ); + kasan_int_result =strcmp (ptr,"2" );pr_info ("use-after-free in strncmp\n" ); -strncmp (ptr,"2" ,1 ); + kasan_int_result =strncmp (ptr,"2" ,1 );pr_info ("use-after-free in strlen\n" ); -strlen (ptr); + kasan_int_result =strlen (ptr);pr_info ("use-after-free in strnlen\n" ); -strnlen (ptr,1 ); + kasan_int_result =strnlen (ptr,1 ); } static noinline void __init kasan_bitops(void)
@@ -743,11 +751,12 @@ static noinline void __init kasan_bitops(void)__test_and_change_bit (BITS_PER_LONG +BITS_PER_BYTE , bits);pr_info ("out-of-bounds in test_bit\n" ); - (void )test_bit (BITS_PER_LONG +BITS_PER_BYTE , bits); + kasan_int_result =test_bit (BITS_PER_LONG +BITS_PER_BYTE , bits);#if defined(clear_bit_unlock_is_negative_byte)pr_info ("out-of-bounds in clear_bit_unlock_is_negative_byte\n" ); -clear_bit_unlock_is_negative_byte (BITS_PER_LONG +BITS_PER_BYTE , bits); + kasan_int_result =clear_bit_unlock_is_negative_byte (BITS_PER_LONG + +BITS_PER_BYTE , bits);#endif kfree (bits); }
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 255/376 string.h: fix incompatibility between FORTIFY_SOURCE and KASAN
In reply to Greg Kroah-HartmanFrom: Daniel Axtens <[email protected]>
[ Upstream commit 47227d27e2fcb01a9e8f5958d8997cf47a820afc ]
The memcmp KASAN self-test fails on a kernel with both KASAN and FORTIFY_SOURCE.
When FORTIFY_SOURCE is on, a number of functions are replaced with fortified versions, which attempt to check the sizes of the operands. However, these functions often directly invoke __builtin_foo() once they have performed the fortify check. Using __builtins may bypass KASAN checks if the compiler decides to inline it's own implementation as sequence of instructions, rather than emit a function call that goes out to a KASAN-instrumented implementation.
Why is only memcmp affected?
============================
Of the string and string-like functions that kasan_test tests, only memcmp is replaced by an inline sequence of instructions in my testing on x86 with gcc version 9.2.1 20191008 (Ubuntu 9.2.1-9ubuntu2).
I believe this is due to compiler heuristics. For example, if I annotate kmalloc calls with the alloc_size annotation (and disable some fortify compile-time checking!), the compiler will replace every memset except the one in kmalloc_uaf_memset with inline instructions. (I have some WIP patches to add this annotation.)
Does this affect other functions in string.h?
=============================================
Yes. Anything that uses __builtin_* rather than __real_* could be affected. This looks like:
- strncpy
- strcat
- strlen
- strlcpy maybe, under some circumstances?
- strncat under some circumstances
- memset
- memcpy
- memmove
- memcmp (as noted)
- memchr
- strcpy
Whether a function call is emitted always depends on the compiler. Most bugs should get caught by FORTIFY_SOURCE, but the missed memcmp test shows that this is not always the case.
Isn't FORTIFY_SOURCE disabled with KASAN?
========================================-
The string headers on all arches supporting KASAN disable fortify with kasan, but only when address sanitisation is _also_ disabled. For example from x86:
#if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__) /*
* For files that are not instrumented (e.g. mm/slub.c) we
* should use not instrumented version of mem* functions. */
#define memcpy(dst, src, len) __memcpy(dst, src, len) #define memmove(dst, src, len) __memmove(dst, src, len) #define memset(s, c, n) __memset(s, c, n)
#ifndef __NO_FORTIFY
#define __NO_FORTIFY /* FORTIFY_SOURCE uses __builtin_memcpy, etc. */ #endif
#endif
This comes from commit 6974f0c4555e ("include/linux/string.h: add the option of fortified string.h functions"), and doesn't work when KASAN is enabled and the file is supposed to be sanitised - as with test_kasan.c
I'm pretty sure this is not wrong, but not as expansive it should be:
* we shouldn't use __builtin_memcpy etc in files where we don't have instrumentation - it could devolve into a function call to memcpy, which will be instrumented. Rather, we should use __memcpy which by convention is not instrumented.
* we also shouldn't be using __builtin_memcpy when we have a KASAN instrumented file, because it could be replaced with inline asm that will not be instrumented.
What is correct behaviour?
==========================
Firstly, there is some overlap between fortification and KASAN: both provide some level of _runtime_ checking. Only fortify provides compile-time checking.
KASAN and fortify can pick up different things at runtime:
- Some fortify functions, notably the string functions, could easily be modified to consider sub-object sizes (e.g. members within a struct), and I have some WIP patches to do this. KASAN cannot detect these because it cannot insert poision between members of a struct.
- KASAN can detect many over-reads/over-writes when the sizes of both operands are unknown, which fortify cannot.
So there are a couple of options:
1) Flip the test: disable fortify in santised files and enable it in unsanitised files. This at least stops us missing KASAN checking, but we lose the fortify checking.
2) Make the fortify code always call out to real versions. Do this only for KASAN, for fear of losing the inlining opportunities we get from __builtin_*.
(We can't use kasan_check_{read,write}: because the fortify functions are _extern inline_, you can't include _static_ inline functions without a compiler warning. kasan_check_{read,write} are static inline so we can't use them even when they would otherwise be suitable.)
Take approach 2 and call out to real versions when KASAN is enabled.
Use __underlying_foo to distinguish from __real_foo: __real_foo always refers to the kernel's implementation of foo, __underlying_foo could be either the kernel implementation or the __builtin_foo implementation.
This is sometimes enough to make the memcmp test succeed with FORTIFY_SOURCE enabled. It is at least enough to get the function call into the module. One more fix is needed to make it reliable: see the next patch.
--- include/linux/string.h | 60 +++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 12 deletions(-)
include/linux/string.h +48 -12
@@ -272,6 +272,31 @@ void __read_overflow3(void) __compiletime_error("detected read beyond size of ob void __write_overflow(void) __compiletime_error("detected write beyond size of object passed as 1st parameter");#if !defined(__NO_FORTIFY) && defined(__OPTIMIZE__) && defined(CONFIG_FORTIFY_SOURCE ) + +#ifdef CONFIG_KASAN +extern void *__underlying_memchr (const void *p,int c,__kernel_size_t size)__RENAME (memchr); +extern int __underlying_memcmp(const void *p, const void *q, __kernel_size_t size) __RENAME(memcmp); +extern void *__underlying_memcpy (void *p,const void *q,__kernel_size_t size)__RENAME (memcpy); +extern void *__underlying_memmove (void *p,const void *q,__kernel_size_t size)__RENAME (memmove); +extern void *__underlying_memset (void *p,int c,__kernel_size_t size)__RENAME (memset); +extern char *__underlying_strcat (char *p,const char *q)__RENAME (strcat); +extern char *__underlying_strcpy (char *p,const char *q)__RENAME (strcpy); +extern __kernel_size_t __underlying_strlen(const char *p) __RENAME(strlen); +extern char *__underlying_strncat (char *p,const char *q,__kernel_size_t count)__RENAME (strncat); +extern char *__underlying_strncpy (char *p,const char *q,__kernel_size_t size)__RENAME (strncpy); +#else +#define __underlying_memchr __builtin_memchr +#define __underlying_memcmp __builtin_memcmp +#define __underlying_memcpy __builtin_memcpy +#define __underlying_memmove __builtin_memmove +#define __underlying_memset __builtin_memset +#define __underlying_strcat __builtin_strcat +#define __underlying_strcpy __builtin_strcpy +#define __underlying_strlen __builtin_strlen +#define __underlying_strncat __builtin_strncat +#define __underlying_strncpy __builtin_strncpy +#endif + __FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size) {size_t p_size =__builtin_object_size (p,0 );
@@ -279,14 +304,14 @@ __FORTIFY_INLINE char *strncpy(char *p, const char *q, __kernel_size_t size)__write_overflow ();if (p_size < size)fortify_panic (__func__); -return __builtin_strncpy (p, q, size); +return __underlying_strncpy (p, q, size); } __FORTIFY_INLINE char *strcat(char *p, const char *q) {size_t p_size =__builtin_object_size (p,0 );if (p_size == (size_t )-1 ) -return __builtin_strcat (p, q); +return __underlying_strcat (p, q);if (strlcat (p, q, p_size) >= p_size)fortify_panic (__func__);return p;
@@ -300,7 +325,7 @@ __FORTIFY_INLINE __kernel_size_t strlen(const char *p)/* Work around gcc excess stack consumption issue */ if (p_size == (size_t )-1 || (__builtin_constant_p (p[p_size -1 ]) && p[p_size -1 ] =='\0' )) -return __builtin_strlen (p); +return __underlying_strlen (p); ret =strnlen (p, p_size);if (p_size <= ret)fortify_panic (__func__);
@@ -333,7 +358,7 @@ __FORTIFY_INLINE size_t strlcpy(char *p, const char *q, size_t size)__write_overflow ();if (len >= p_size)fortify_panic (__func__); -__builtin_memcpy (p, q, len); +__underlying_memcpy (p, q, len); p[len] ='\0' ; }return ret;
@@ -346,12 +371,12 @@ __FORTIFY_INLINE char *strncat(char *p, const char *q, __kernel_size_t count)size_t p_size =__builtin_object_size (p,0 );size_t q_size =__builtin_object_size (q,0 );if (p_size == (size_t )-1 && q_size == (size_t )-1 ) -return __builtin_strncat (p, q, count); +return __underlying_strncat (p, q, count); p_len =strlen (p); copy_len =strnlen (q, count);if (p_size < p_len + copy_len +1 )fortify_panic (__func__); -__builtin_memcpy (p + p_len, q, copy_len); +__underlying_memcpy (p + p_len, q, copy_len); p[p_len + copy_len] ='\0' ;return p; }
@@ -363,7 +388,7 @@ __FORTIFY_INLINE void *memset(void *p, int c, __kernel_size_t size)__write_overflow ();if (p_size < size)fortify_panic (__func__); -return __builtin_memset (p, c, size); +return __underlying_memset (p, c, size); } __FORTIFY_INLINE void *memcpy(void *p, const void *q, __kernel_size_t size)
@@ -378,7 +403,7 @@ __FORTIFY_INLINE void *memcpy(void *p, const void *q, __kernel_size_t size) }if (p_size < size || q_size < size)fortify_panic (__func__); -return __builtin_memcpy (p, q, size); +return __underlying_memcpy (p, q, size); } __FORTIFY_INLINE void *memmove(void *p, const void *q, __kernel_size_t size)
@@ -393,7 +418,7 @@ __FORTIFY_INLINE void *memmove(void *p, const void *q, __kernel_size_t size) }if (p_size < size || q_size < size)fortify_panic (__func__); -return __builtin_memmove (p, q, size); +return __underlying_memmove (p, q, size); }extern void *__real_memscan (void *,int ,__kernel_size_t )__RENAME (memscan);
@@ -419,7 +444,7 @@ __FORTIFY_INLINE int memcmp(const void *p, const void *q, __kernel_size_t size) }if (p_size < size || q_size < size)fortify_panic (__func__); -return __builtin_memcmp (p, q, size); +return __underlying_memcmp (p, q, size); } __FORTIFY_INLINE void *memchr(const void *p, int c, __kernel_size_t size)
@@ -429,7 +454,7 @@ __FORTIFY_INLINE void *memchr(const void *p, int c, __kernel_size_t size)__read_overflow ();if (p_size < size)fortify_panic (__func__); -return __builtin_memchr (p, c, size); +return __underlying_memchr (p, c, size); }void *__real_memchr_inv (const void *s,int c,size_t n)__RENAME (memchr_inv);
@@ -460,11 +485,22 @@ __FORTIFY_INLINE char *strcpy(char *p, const char *q)size_t p_size =__builtin_object_size (p,0 );size_t q_size =__builtin_object_size (q,0 );if (p_size == (size_t )-1 && q_size == (size_t )-1 ) -return __builtin_strcpy (p, q); +return __underlying_strcpy (p, q);memcpy (p, q,strlen (q) +1 ); return p; } +/* Don't use these outside the FORITFY_SOURCE implementation */ +#undef __underlying_memchr +#undef __underlying_memcmp +#undef __underlying_memcpy +#undef __underlying_memmove +#undef __underlying_memset +#undef __underlying_strcat +#undef __underlying_strcpy +#undef __underlying_strlen +#undef __underlying_strncat +#undef __underlying_strncpy#endif /**
Signature · 1 line
2.25.1
Greg Kroah-Hartman
maintainerPATCH 256/376 btrfs: free alien device after device add
In reply to Greg Kroah-HartmanFrom: Anand Jain <[email protected]>
commit 7f551d969037cc128eca60688d9c5a300d84e665 upstream.
When an old device has new fsid through 'btrfs device add -f <dev>' our fs_devices list has an alien device in one of the fs_devices lists.
By having an alien device in fs_devices, we have two issues so far
1. missing device does not not show as missing in the userland
2. degraded mount will fail
Both issues are caused by the fact that there's an alien device in the fs_devices list. (Alien means that it does not belong to the filesystem, identified by fsid, or does not contain btrfs filesystem at all, eg. due to overwrite).
A device can be scanned/added through the control device ioctls SCAN_DEV, DEVICES_READY or by ADD_DEV.
And device coming through the control device is checked against the all other devices in the lists, but this was not the case for ADD_DEV.
This patch fixes both issues above by removing the alien device.
--- fs/btrfs/volumes.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
fs/btrfs/volumes.c +11 -1
@@ -2663,8 +2663,18 @@ int btrfs_init_new_device(struct btrfs_f ret =btrfs_commit_transaction (trans); } -/* Update ctime/mtime for libblkid */ +/* +* Now that we have written a new super block to this device, check all +* other fs_devices list if device_path alienates any other scanned +* device. +* We can ignore the return value as it typically returns -EINVAL and +* only succeeds if the device was an alien. +*/ +btrfs_forget_devices (device_path); + +/* Update ctime/mtime for blkid or udev */ update_dev_time (device_path); +return ret; error_sysfs:
Greg Kroah-Hartman
maintainerPATCH 257/376 btrfs: include non-missing as a qualifier for the latest_bdev
In reply to Greg Kroah-HartmanFrom: Anand Jain <[email protected]>
commit 998a0671961f66e9fad4990ed75f80ba3088c2f1 upstream.
btrfs_free_extra_devids() updates fs_devices::latest_bdev to point to the bdev with greatest device::generation number. For a typical-missing device the generation number is zero so fs_devices::latest_bdev will never point to it.
But if the missing device is due to alienation [1], then device::generation is not zero and if it is greater or equal to the rest of device generations in the list, then fs_devices::latest_bdev ends up pointing to the missing device and reports the error like [2].
[1] We maintain devices of a fsid (as in fs_device::fsid) in the fs_devices::devices list, a device is considered as an alien device if its fsid does not match with the fs_device::fsid
Consider a working filesystem with raid1:
$ mkfs.btrfs -f -d raid1 -m raid1 /dev/sda /dev/sdb $ mount /dev/sda /mnt-raid1 $ umount /mnt-raid1
While mnt-raid1 was unmounted the user force-adds one of its devices to another btrfs filesystem:
$ mkfs.btrfs -f /dev/sdc $ mount /dev/sdc /mnt-single $ btrfs dev add -f /dev/sda /mnt-single
Now the original mnt-raid1 fails to mount in degraded mode, because fs_devices::latest_bdev is pointing to the alien device.
$ mount -o degraded /dev/sdb /mnt-raid1
[2]
mount: wrong fs type, bad option, bad superblock on /dev/sdb,
missing codepage or helper program, or other error
In some cases useful info is found in syslog - try dmesg | tail or so.
kernel: BTRFS warning (device sdb): devid 1 uuid 072a0192-675b-4d5a-8640-a5cf2b2c704d is missing
kernel: BTRFS error (device sdb): failed to read devices
kernel: BTRFS error (device sdb): open_ctree failed
Fix the root cause by checking if the device is not missing before it can be considered for the fs_devices::latest_bdev.
--- fs/btrfs/volumes.c | 2 ++ 1 file changed, 2 insertions(+)
fs/btrfs/volumes.c +2 -0
@@ -1042,6 +1042,8 @@ again: &device->dev_state)) {if (!test_bit (BTRFS_DEV_STATE_REPLACE_TGT , &device->dev_state) && + !test_bit (BTRFS_DEV_STATE_MISSING , + &device->dev_state) && (!latest_dev || device->generation > latest_dev->generation)) { latest_dev = device;
Greg Kroah-Hartman
maintainerPATCH 258/376 btrfs: fix a race between scrub and block group removal/allocation
In reply to Greg Kroah-HartmanFrom: Filipe Manana <[email protected]>
commit 2473d24f2b77da0ffabcbb916793e58e7f57440b upstream.
When scrub is verifying the extents of a block group for a device, it is possible that the corresponding block group gets removed and its logical address and device extents get used for a new block group allocation. When this happens scrub incorrectly reports that errors were detected and, if the the new block group has a different profile then the old one, deleted block group, we can crash due to a null pointer dereference. Possibly other unexpected and weird consequences can happen as well.
Consider the following sequence of actions that leads to the null pointer dereference crash when scrub is running in parallel with balance:
1) Balance sets block group X to read-only mode and starts relocating it. Block group X is a metadata block group, has a raid1 profile (two device extents, each one in a different device) and a logical address of 19424870400;
2) Scrub is running and finds device extent E, which belongs to block group X. It enters scrub_stripe() to find all extents allocated to block group X, the search is done using the extent tree;
3) Balance finishes relocating block group X and removes block group X;
4) Balance starts relocating another block group and when trying to commit the current transaction as part of the preparation step (prepare_to_relocate()), it blocks because scrub is running;
5) The scrub task finds the metadata extent at the logical address 19425001472 and marks the pages of the extent to be read by a bio (struct scrub_bio). The extent item's flags, which have the bit BTRFS_EXTENT_FLAG_TREE_BLOCK set, are added to each page (struct scrub_page). It is these flags in the scrub pages that tells the bio's end io function (scrub_bio_end_io_worker) which type of extent it is dealing with. At this point we end up with 4 pages in a bio which is ready for submission (the metadata extent has a size of 16Kb, so that gives 4 pages on x86);
6) At the next iteration of scrub_stripe(), scrub checks that there is a pause request from the relocation task trying to commit a transaction, therefore it submits the pending bio and pauses, waiting for the transaction commit to complete before resuming;
7) The relocation task commits the transaction. The device extent E, that was used by our block group X, is now available for allocation, since the commit root for the device tree was swapped by the transaction commit;
8) Another task doing a direct IO write allocates a new data block group Y which ends using device extent E. This new block group Y also ends up getting the same logical address that block group X had: 19424870400. This happens because block group X was the block group with the highest logical address and, when allocating Y, find_next_chunk() returns the end offset of the current last block group to be used as the logical address for the new block group, which is
18351128576 + 1073741824 = 19424870400
So our new block group Y has the same logical address and device extent that block group X had. However Y is a data block group, while X was a metadata one, and Y has a raid0 profile, while X had a raid1 profile;
9) After allocating block group Y, the direct IO submits a bio to write to device extent E;
10) The read bio submitted by scrub reads the 4 pages (16Kb) from device
extent E, which now correspond to the data written by the task that
did a direct IO write. Then at the end io function associated with
the bio, scrub_bio_end_io_worker(), we call scrub_block_complete()
which calls scrub_checksum(). This later function checks the flags
of the first page, and sees that the bit BTRFS_EXTENT_FLAG_TREE_BLOCK
is set in the flags, so it assumes it has a metadata extent and
then calls scrub_checksum_tree_block(). That functions returns an
error, since interpreting data as a metadata extent causes the
checksum verification to fail.
So this makes scrub_checksum() call scrub_handle_errored_block(),
which determines 'failed_mirror_index' to be 1, since the device
extent E was allocated as the second mirror of block group X.
It allocates BTRFS_MAX_MIRRORS scrub_block structures as an array at
'sblocks_for_recheck', and all the memory is initialized to zeroes by
kcalloc().
After that it calls scrub_setup_recheck_block(), which is responsible
for filling each of those structures. However, when that function
calls btrfs_map_sblock() against the logical address of the metadata
extent, 19425001472, it gets a struct btrfs_bio ('bbio') that matches
the current block group Y. However block group Y has a raid0 profile
and not a raid1 profile like X had, so the following call returns 1:
scrub_nr_raid_mirrors(bbio)
And as a result scrub_setup_recheck_block() only initializes the
first (index 0) scrub_block structure in 'sblocks_for_recheck'.
Then scrub_recheck_block() is called by scrub_handle_errored_block()
with the second (index 1) scrub_block structure as the argument,
because 'failed_mirror_index' was previously set to 1.
This scrub_block was not initialized by scrub_setup_recheck_block(),
so it has zero pages, its 'page_count' member is 0 and its 'pagev'
page array has all members pointing to NULL.
Finally when scrub_recheck_block() calls scrub_recheck_block_checksum()
we have a NULL pointer dereference when accessing the flags of the first
page, as pavev[0] is NULL:
static void scrub_recheck_block_checksum(struct scrub_block *sblock)
{
(...)
if (sblock->pagev[0]->flags & BTRFS_EXTENT_FLAG_DATA)
scrub_checksum_data(sblock);
(...)
}
Producing a stack trace like the following:
[542998.008985] BUG: kernel NULL pointer dereference, address: 0000000000000028
[542998.010238] #PF: supervisor read access in kernel mode
[542998.010878] #PF: error_code(0x0000) - not-present page
[542998.011516] PGD 0 P4D 0
[542998.011929] Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC PTI
[542998.012786] CPU: 3 PID: 4846 Comm: kworker/u8:1 Tainted: G B W 5.6.0-rc7-btrfs-next-58 #1
[542998.014524] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba5276e321-prebuilt.qemu.org 04/01/2014
[542998.016065] Workqueue: btrfs-scrub btrfs_work_helper [btrfs]
[542998.017255] RIP: 0010:scrub_recheck_block_checksum+0xf/0x20 [btrfs]
[542998.018474] Code: 4c 89 e6 ...
[542998.021419] RSP: 0018:ffffa7af0375fbd8 EFLAGS: 00010202
[542998.022120] RAX: 0000000000000000 RBX: ffff9792e674d120 RCX: 0000000000000000
[542998.023178] RDX: 0000000000000001 RSI: ffff9792e674d120 RDI: ffff9792e674d120
[542998.024465] RBP: 0000000000000000 R08: 0000000000000067 R09: 0000000000000001
[542998.025462] R10: ffffa7af0375fa50 R11: 0000000000000000 R12: ffff9791f61fe800
[542998.026357] R13: ffff9792e674d120 R14: 0000000000000001 R15: ffffffffc0e3dfc0
[542998.027237] FS: 0000000000000000(0000) GS:ffff9792fb200000(0000) knlGS:0000000000000000
[542998.028327] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[542998.029261] CR2: 0000000000000028 CR3: 00000000b3b18003 CR4: 00000000003606e0
[542998.030301] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[542998.031316] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[542998.032380] Call Trace:
[542998.032752] scrub_recheck_block+0x162/0x400 [btrfs]
[542998.033500] ? __alloc_pages_nodemask+0x31e/0x460
[542998.034228] scrub_handle_errored_block+0x6f8/0x1920 [btrfs]
[542998.035170] scrub_bio_end_io_worker+0x100/0x520 [btrfs]
[542998.035991] btrfs_work_helper+0xaa/0x720 [btrfs]
[542998.036735] process_one_work+0x26d/0x6a0
[542998.037275] worker_thread+0x4f/0x3e0
[542998.037740] ? process_one_work+0x6a0/0x6a0
[542998.038378] kthread+0x103/0x140
[542998.038789] ? kthread_create_worker_on_cpu+0x70/0x70
[542998.039419] ret_from_fork+0x3a/0x50
[542998.039875] Modules linked in: dm_snapshot dm_thin_pool ...
[542998.047288] CR2: 0000000000000028
[542998.047724] ---[ end trace bde186e176c7f96a ]---This issue has been around for a long time, possibly since scrub exists. The last time I ran into it was over 2 years ago. After recently fixing fstests to pass the "--full-balance" command line option to btrfs-progs when doing balance, several tests started to more heavily exercise balance with fsstress, scrub and other operations in parallel, and therefore started to hit this issue again (with btrfs/061 for example).
Fix this by having scrub increment the 'trimming' counter of the block group, which pins the block group in such a way that it guarantees neither its logical address nor device extents can be reused by future block group allocations until we decrement the 'trimming' counter. Also make sure that on each iteration of scrub_stripe() we stop scrubbing the block group if it was removed already.
A later patch in the series will rename the block group's 'trimming' counter and its helpers to a more generic name, since now it is not used exclusively for pinning while trimming anymore.
--- fs/btrfs/scrub.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-)
fs/btrfs/scrub.c +36 -2
@@ -3046,7 +3046,8 @@ out: static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,struct map_lookup *map,struct btrfs_device *scrub_dev, -int num,u64 base,u64 length) +int num,u64 base,u64 length, +struct btrfs_block_group *cache) {struct btrfs_path *path, *ppath;struct btrfs_fs_info *fs_info = sctx->fs_info;
@@ -3284,6 +3285,20 @@ static noinline_for_stack int scrub_stribreak ; } +/* +* If our block group was removed in the meanwhile, just +* stop scrubbing since there is no point in continuing. +* Continuing would prevent reusing its device extents +* for new block groups for a long time. +*/ +spin_lock (&cache->lock); +if (cache->removed) { +spin_unlock (&cache->lock); + ret =0 ; + goto out; + } +spin_unlock (&cache->lock); + extent =btrfs_item_ptr (l, slot, struct btrfs_extent_item); flags =btrfs_extent_flags (l, extent);
@@ -3457,7 +3472,7 @@ static noinline_for_stack int scrub_chunif (map->stripes[i].dev->bdev == scrub_dev->bdev && map->stripes[i].physical == dev_offset) { ret =scrub_stripe (sctx, map, scrub_dev, i, - chunk_offset, length); + chunk_offset, length, cache);if (ret) goto out; }
@@ -3555,6 +3570,23 @@ int scrub_enumerate_chunks(struct scrub_ goto skip;/* +* Make sure that while we are scrubbing the corresponding block +* group doesn't get its logical address and its device extents +* reused for another block group, which can possibly be of a +* different type and different profile. We do this to prevent +* false error detections and crashes due to bogus attempts to +* repair extents. +*/ +spin_lock (&cache->lock); +if (cache->removed) { +spin_unlock (&cache->lock); +btrfs_put_block_group (cache); + goto skip; + } +btrfs_get_block_group_trimming (cache); +spin_unlock (&cache->lock); + +/* * we need call btrfs_inc_block_group_ro() with scrubs_paused, * to avoid deadlock caused by: * btrfs_inc_block_group_ro()
@@ -3609,6 +3641,7 @@ int scrub_enumerate_chunks(struct scrub_ }else {btrfs_warn (fs_info,"failed setting block group ro: %d" , ret); +btrfs_put_block_group_trimming (cache);btrfs_put_block_group (cache);scrub_pause_off (fs_info);break ;
@@ -3695,6 +3728,7 @@ int scrub_enumerate_chunks(struct scrub_spin_unlock (&cache->lock); } +btrfs_put_block_group_trimming (cache);btrfs_put_block_group (cache);if (ret)break ;
Greg Kroah-Hartman
maintainerPATCH 259/376 btrfs: send: emit file capabilities after chown
In reply to Greg Kroah-HartmanFrom: Marcos Paulo de Souza <[email protected]>
commit 89efda52e6b6930f80f5adda9c3c9edfb1397191 upstream.
Whenever a chown is executed, all capabilities of the file being touched are lost. When doing incremental send with a file with capabilities, there is a situation where the capability can be lost on the receiving side. The sequence of actions bellow shows the problem:
$ mount /dev/sda fs1 $ mount /dev/sdb fs2
$ touch fs1/foo.bar $ setcap cap_sys_nice+ep fs1/foo.bar $ btrfs subvolume snapshot -r fs1 fs1/snap_init $ btrfs send fs1/snap_init | btrfs receive fs2
$ chgrp adm fs1/foo.bar $ setcap cap_sys_nice+ep fs1/foo.bar
$ btrfs subvolume snapshot -r fs1 fs1/snap_complete $ btrfs subvolume snapshot -r fs1 fs1/snap_incremental
$ btrfs send fs1/snap_complete | btrfs receive fs2 $ btrfs send -p fs1/snap_init fs1/snap_incremental | btrfs receive fs2
At this point, only a chown was emitted by "btrfs send" since only the group was changed. This makes the cap_sys_nice capability to be dropped from fs2/snap_incremental/foo.bar
To fix that, only emit capabilities after chown is emitted. The current code first checks for xattrs that are new/changed, emits them, and later emit the chown. Now, __process_new_xattr skips capabilities, letting only finish_inode_if_needed to emit them, if they exist, for the inode being processed.
This behavior was being worked around in "btrfs receive" side by caching the capability and only applying it after chown. Now, xattrs are only emmited _after_ chown, making that workaround not needed anymore.
--- fs/btrfs/send.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+)
fs/btrfs/send.c +67 -0
@@ -23,6 +23,7 @@#include "btrfs_inode.h" #include "transaction.h" #include "compression.h" +#include "xattr.h" /* * Maximum number of references an extent can have in order for us to attempt to
@@ -4545,6 +4546,10 @@ static int __process_new_xattr(int num,struct fs_path *p;struct posix_acl_xattr_header dummy_acl; +/* Capabilities are emitted by finish_inode_if_needed */ +if (!strncmp (name,XATTR_NAME_CAPS , name_len)) +return 0 ; + p =fs_path_alloc ();if (!p)return -ENOMEM ;
@@ -5107,6 +5112,64 @@ static int send_extent_data(struct send_return 0 ; } +/* +* Search for a capability xattr related to sctx->cur_ino. If the capability is +* found, call send_set_xattr function to emit it. +* +* Return 0 if there isn't a capability, or when the capability was emitted +* successfully, or < 0 if an error occurred. +*/ +static int send_capabilities (struct send_ctx *sctx) +{ +struct fs_path *fspath =NULL ; +struct btrfs_path *path; +struct btrfs_dir_item *di; +struct extent_buffer *leaf; +unsigned long data_ptr; +char *buf =NULL ; +int buf_len; +int ret =0 ; + + path =alloc_path_for_send (); +if (!path) +return -ENOMEM ; + + di =btrfs_lookup_xattr (NULL , sctx->send_root, path, sctx->cur_ino, +XATTR_NAME_CAPS ,strlen (XATTR_NAME_CAPS ),0 ); +if (!di) { +/* There is no xattr for this inode */ + goto out; + }else if (IS_ERR (di)) { + ret =PTR_ERR (di); + goto out; + } + + leaf = path->nodes[0 ]; + buf_len =btrfs_dir_data_len (leaf, di); + + fspath =fs_path_alloc (); + buf =kmalloc (buf_len,GFP_KERNEL ); +if (!fspath || !buf) { + ret = -ENOMEM ; + goto out; + } + + ret =get_cur_path (sctx, sctx->cur_ino, sctx->cur_inode_gen, fspath); +if (ret <0 ) + goto out; + + data_ptr = (unsigned long )(di +1 ) +btrfs_dir_name_len (leaf, di); +read_extent_buffer (leaf, buf, data_ptr, buf_len); + + ret =send_set_xattr (sctx, fspath,XATTR_NAME_CAPS , +strlen (XATTR_NAME_CAPS ), buf, buf_len); +out: +kfree (buf); +fs_path_free (fspath); +btrfs_free_path (path); +return ret; +} + static int clone_range(struct send_ctx *sctx, struct clone_root *clone_root, const u64 disk_byte,
@@ -5972,6 +6035,10 @@ static int finish_inode_if_needed(struct goto out; } + ret =send_capabilities (sctx); +if (ret <0 ) + goto out; +/* * If other directory inodes depended on our current directory * inode's move/rename, now do their move/rename operations.
Greg Kroah-Hartman
maintainerPATCH 260/376 btrfs: force chunk allocation if our global rsv is larger than metadata
In reply to Greg Kroah-HartmanFrom: Josef Bacik <[email protected]>
commit 9c343784c4328781129bcf9e671645f69fe4b38a upstream.
Nikolay noticed a bunch of test failures with my global rsv steal patches. At first he thought they were introduced by them, but they've been failing for a while with 64k nodes.
The problem is with 64k nodes we have a global reserve that calculates out to 13MiB on a freshly made file system, which only has 8MiB of metadata space. Because of changes I previously made we no longer account for the global reserve in the overcommit logic, which means we correctly allow overcommit to happen even though we are already overcommitted.
However in some corner cases, for example btrfs/170, we will allocate the entire file system up with data chunks before we have enough space pressure to allocate a metadata chunk. Then once the fs is full we ENOSPC out because we cannot overcommit and the global reserve is taking up all of the available space.
The most ideal way to deal with this is to change our space reservation stuff to take into account the height of the tree's that we're modifying, so that our global reserve calculation does not end up so obscenely large.
However that is a huge undertaking. Instead fix this by forcing a chunk allocation if the global reserve is larger than the total metadata space. This gives us essentially the same behavior that happened before, we get a chunk allocated and these tests can pass.
This is meant to be a stop-gap measure until we can tackle the "tree height only" project.
--- fs/btrfs/block-rsv.c | 3 +++ fs/btrfs/transaction.c | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+)
fs/btrfs/block-rsv.c +3 -0
@@ -5,6 +5,7 @@#include "block-rsv.h" #include "space-info.h" #include "transaction.h" +#include "block-group.h" /* * HOW DO BLOCK RESERVES WORK
@@ -405,6 +406,8 @@ void btrfs_update_global_block_rsv(strucelse block_rsv->full =0 ; +if (block_rsv->size >= sinfo->total_bytes) + sinfo->force_alloc =CHUNK_ALLOC_FORCE ;spin_unlock (&block_rsv->lock);spin_unlock (&sinfo->lock); }
fs/btrfs/transaction.c +18 -0
@@ -21,6 +21,7 @@#include "dev-replace.h" #include "qgroup.h" #include "block-group.h" +#include "space-info.h" #define BTRFS_ROOT_TRANS_TAG 0
@@ -523,6 +524,7 @@ start_transaction(struct btrfs_root *roou64 num_bytes =0 ;u64 qgroup_reserved =0 ;bool reloc_reserved = false; +bool do_chunk_alloc = false;int ret;/* Send isn't supposed to start transactions. */
@@ -585,6 +587,9 @@ start_transaction(struct btrfs_root *roo delayed_refs_bytes); num_bytes -= delayed_refs_bytes; } + +if (rsv->space_info->force_alloc) + do_chunk_alloc = true; }else if (num_items ==0 && flush ==BTRFS_RESERVE_FLUSH_ALL && !delayed_refs_rsv->full) {/*
@@ -667,6 +672,19 @@ got_it: current->journal_info = h;/* +* If the space_info is marked ALLOC_FORCE then we'll get upgraded to +* ALLOC_FORCE the first run through, and then we won't allocate for +* anybody else who races in later. We don't care about the return +* value here. +*/ +if (do_chunk_alloc && num_bytes) { +u64 flags = h->block_rsv->space_info->flags; + +btrfs_chunk_alloc (h,btrfs_get_alloc_profile (fs_info, flags), +CHUNK_ALLOC_NO_FORCE ); + } + +/* * btrfs_record_root_in_trans() needs to alloc new extents, and may * call btrfs_join_transaction() while we're also starting a * transaction.
Greg Kroah-Hartman
maintainerPATCH 261/376 btrfs: reloc: fix reloc root leak and NULL pointer dereference
In reply to Greg Kroah-HartmanFrom: Qu Wenruo <[email protected]>
commit 51415b6c1b117e223bc083e30af675cb5c5498f3 upstream.
[BUG]
When balance is canceled, there is a pretty high chance that unmounting the fs can lead to lead the NULL pointer dereference:
BTRFS warning (device dm-3): page private not zero on page 223158272
...
BTRFS warning (device dm-3): page private not zero on page 223162368 BTRFS error (device dm-3): leaked root 18446744073709551608-304 refcount 1
BUG: kernel NULL pointer dereference, address: 0000000000000168 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 0 P4D 0 Oops: 0000 [#1] PREEMPT SMP NOPTI CPU: 2 PID: 5793 Comm: umount Tainted: G O 5.7.0-rc5-custom+ #53 Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 RIP: 0010:__lock_acquire+0x5dc/0x24c0 Call Trace: lock_acquire+0xab/0x390 _raw_spin_lock+0x39/0x80 btrfs_release_extent_buffer_pages+0xd7/0x200 [btrfs] release_extent_buffer+0xb2/0x170 [btrfs] free_extent_buffer+0x66/0xb0 [btrfs] btrfs_put_root+0x8e/0x130 [btrfs] btrfs_check_leaked_roots.cold+0x5/0x5d [btrfs] btrfs_free_fs_info+0xe5/0x120 [btrfs] btrfs_kill_super+0x1f/0x30 [btrfs] deactivate_locked_super+0x3b/0x80 deactivate_super+0x3e/0x50 cleanup_mnt+0x109/0x160 __cleanup_mnt+0x12/0x20 task_work_run+0x67/0xa0 exit_to_usermode_loop+0xc5/0xd0 syscall_return_slowpath+0x205/0x360 do_syscall_64+0x6e/0xb0 entry_SYSCALL_64_after_hwframe+0x49/0xb3 RIP: 0033:0x7fd028ef740b
[CAUSE]
When balance is canceled, all reloc roots are marked as orphan, and orphan reloc roots are going to be cleaned up.
However for orphan reloc roots and merged reloc roots, their lifespan are quite different:
Merged reloc roots | Orphan reloc roots by cancel
--------------------------------------------------------------------create_reloc_root() | create_reloc_root()
|- refs == 1 | |- refs == 1
|
btrfs_grab_root(reloc_root); | btrfs_grab_root(reloc_root);
|- refs == 2 | |- refs == 2
|
root->reloc_root = reloc_root; | root->reloc_root = reloc_root;
>>> No difference so far <<<
|
prepare_to_merge() | prepare_to_merge()
|- btrfs_set_root_refs(item, 1);| |- if (!err) (err == -EINTR)
|
merge_reloc_roots() | merge_reloc_roots()
|- merge_reloc_root() | |- Doing nothing to put reloc root
|- insert_dirty_subvol() | |- refs == 2
|- __del_reloc_root() |
|- btrfs_put_root() |
|- refs == 1 |
>>> Now orphan reloc roots still have refs 2 <<<
|
clean_dirty_subvols() | clean_dirty_subvols()
|- btrfs_drop_snapshot() | |- btrfS_drop_snapshot()
|- reloc_root get freed | |- reloc_root still has refs 2
| related ebs get freed, but
| reloc_root still recorded in
| allocated_roots
btrfs_check_leaked_roots() | btrfs_check_leaked_roots()
|- No leaked roots | |- Leaked reloc_roots detected
| |- btrfs_put_root()
| |- free_extent_buffer(root->node);
| |- eb already freed, caused NULL
| pointer dereference[FIX]
The fix is to clear fs_root->reloc_root and put it at merge_reloc_roots() time, so that we won't leak reloc roots.
--- fs/btrfs/relocation.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
fs/btrfs/relocation.c +9 -3
@@ -2624,12 +2624,10 @@ again: reloc_root =list_entry (reloc_roots.next, struct btrfs_root, root_list); + root =read_fs_root (fs_info, reloc_root->root_key.offset);if (btrfs_root_refs (&reloc_root->root_item) >0 ) { - root =read_fs_root (fs_info, - reloc_root->root_key.offset);BUG_ON (IS_ERR (root));BUG_ON (root->reloc_root != reloc_root); - ret =merge_reloc_root (rc, root);btrfs_put_root (root);if (ret) {
@@ -2639,6 +2637,14 @@ again: goto out; } }else { +if (!IS_ERR (root)) { +if (root->reloc_root == reloc_root) { + root->reloc_root =NULL ; +btrfs_put_root (reloc_root); + } +btrfs_put_root (root); + } +list_del_init (&reloc_root->root_list);/* Don't forget to queue this reloc root for cleanup */ list_add_tail(&reloc_root->reloc_dirty_list,
Greg Kroah-Hartman
maintainerPATCH 262/376 btrfs: fix error handling when submitting direct I/O bio
In reply to Greg Kroah-HartmanFrom: Omar Sandoval <[email protected]>
commit 6d3113a193e3385c72240096fe397618ecab6e43 upstream.
In btrfs_submit_direct_hook(), if a direct I/O write doesn't span a RAID stripe or chunk, we submit orig_bio without cloning it. In this case, we don't increment pending_bios. Then, if btrfs_submit_dio_bio() fails, we decrement pending_bios to -1, and we never complete orig_bio. Fix it by initializing pending_bios to 1 instead of incrementing later.
Fixing this exposes another bug: we put orig_bio prematurely and then put it again from end_io. Fix it by not putting orig_bio.
After this change, pending_bios is really more of a reference count, but I'll leave that cleanup separate to keep the fix small.
--- fs/btrfs/inode.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
fs/btrfs/inode.c +3 -3
@@ -7939,7 +7939,6 @@ static int btrfs_submit_direct_hook(stru/* bio split */ ASSERT (geom.len <=INT_MAX ); -atomic_inc (&dip->pending_bios); do { clone_len = min_t(int, submit_len, geom.len);
@@ -7989,7 +7988,8 @@ submit:if (!status)return 0 ; -bio_put (bio); +if (bio != orig_bio) +bio_put (bio); out_err: dip->errors =1 ;/*
@@ -8030,7 +8030,7 @@ static void btrfs_submit_direct(struct b bio->bi_private = dip; dip->orig_bio = bio; dip->dio_bio = dio_bio; -atomic_set (&dip->pending_bios,0 ); +atomic_set (&dip->pending_bios,1 ); io_bio =btrfs_io_bio (bio); io_bio->logical = file_offset;
Greg Kroah-Hartman
maintainerPATCH 263/376 btrfs: fix corrupt log due to concurrent fsync of inodes with shared extents
In reply to Greg Kroah-HartmanFrom: Filipe Manana <[email protected]>
commit e289f03ea79bbc6574b78ac25682555423a91cbb upstream.
When we have extents shared amongst different inodes in the same subvolume, if we fsync them in parallel we can end up with checksum items in the log tree that represent ranges which overlap.
For example, consider we have inodes A and B, both sharing an extent that covers the logical range from X to X + 64KiB:
1) Task A starts an fsync on inode A;
2) Task B starts an fsync on inode B;
3) Task A calls btrfs_csum_file_blocks(), and the first search in the log tree, through btrfs_lookup_csum(), returns -EFBIG because it finds an existing checksum item that covers the range from X - 64KiB to X;
4) Task A checks that the checksum item has not reached the maximum possible size (MAX_CSUM_ITEMS) and then releases the search path before it does another path search for insertion (through a direct call to btrfs_search_slot());
5) As soon as task A releases the path and before it does the search for insertion, task B calls btrfs_csum_file_blocks() and gets -EFBIG too, because there is an existing checksum item that has an end offset that matches the start offset (X) of the checksum range we want to log;
6) Task B releases the path;
7) Task A does the path search for insertion (through btrfs_search_slot()) and then verifies that the checksum item that ends at offset X still exists and extends its size to insert the checksums for the range from X to X + 64KiB;
8) Task A releases the path and returns from btrfs_csum_file_blocks(), having inserted the checksums into an existing checksum item that got its size extended. At this point we have one checksum item in the log tree that covers the logical range from X - 64KiB to X + 64KiB;
9) Task B now does a search for insertion using btrfs_search_slot() too, but it finds that the previous checksum item no longer ends at the offset X, it now ends at an of offset X + 64KiB, so it leaves that item untouched.
Then it releases the path and calls btrfs_insert_empty_item() that inserts a checksum item with a key offset corresponding to X and a size for inserting a single checksum (4 bytes in case of crc32c). Subsequent iterations end up extending this new checksum item so that it contains the checksums for the range from X to X + 64KiB.
So after task B returns from btrfs_csum_file_blocks() we end up with two checksum items in the log tree that have overlapping ranges, one for the range from X - 64KiB to X + 64KiB, and another for the range from X to X + 64KiB.
Having checksum items that represent ranges which overlap, regardless of being in the log tree or in the chekcsums tree, can lead to problems where checksums for a file range end up not being found. This type of problem has happened a few times in the past and the following commits fixed them and explain in detail why having checksum items with overlapping ranges is problematic:
27b9a8122ff71a "Btrfs: fix csum tree corruption, duplicate and outdated checksums" b84b8390d6009c "Btrfs: fix file read corruption after extent cloning and fsync" 40e046acbd2f36 "Btrfs: fix missing data checksums after replaying a log tree"
Since this specific instance of the problem can only happen when logging inodes, because it is the only case where concurrent attempts to insert checksums for the same range can happen, fix the issue by using an extent io tree as a range lock to serialize checksum insertion during inode logging.
This issue could often be reproduced by the test case generic/457 from fstests. When it happens it produces the following trace:
BTRFS critical (device dm-0): corrupt leaf: root=18446744073709551610 block=30625792 slot=42, csum end range (15020032) goes beyond the start range (15015936) of the next csum item BTRFS info (device dm-0): leaf 30625792 gen 7 total ptrs 49 free space 2402 owner 18446744073709551610
BTRFS info (device dm-0): refs 1 lock (w:0 r:0 bw:0 br:0 sw:0 sr:0) lock_owner 0 current 15884
item 0 key (18446744073709551606 128 13979648) itemoff 3991 itemsize 4
item 1 key (18446744073709551606 128 13983744) itemoff 3987 itemsize 4
item 2 key (18446744073709551606 128 13987840) itemoff 3983 itemsize 4
item 3 key (18446744073709551606 128 13991936) itemoff 3979 itemsize 4
item 4 key (18446744073709551606 128 13996032) itemoff 3975 itemsize 4
item 5 key (18446744073709551606 128 14000128) itemoff 3971 itemsize 4
(...)
BTRFS error (device dm-0): block=30625792 write time tree block corruption detected
------------[ cut here ]------------
WARNING: CPU: 1 PID: 15884 at fs/btrfs/disk-io.c:539 btree_csum_one_bio+0x268/0x2d0 [btrfs]
Modules linked in: btrfs dm_thin_pool ...
CPU: 1 PID: 15884 Comm: fsx Tainted: G W 5.6.0-rc7-btrfs-next-58 #1
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba5276e321-prebuilt.qemu.org 04/01/2014
RIP: 0010:btree_csum_one_bio+0x268/0x2d0 [btrfs]
Code: c7 c7 ...
RSP: 0018:ffffbb0109e6f8e0 EFLAGS: 00010296
RAX: 0000000000000000 RBX: ffffe1c0847b6080 RCX: 0000000000000000
RDX: 0000000000000000 RSI: ffffffffaa963988 RDI: 0000000000000001
RBP: ffff956a4f4d2000 R08: 0000000000000000 R09: 0000000000000001
R10: 0000000000000526 R11: 0000000000000000 R12: ffff956a5cd28bb0
R13: 0000000000000000 R14: ffff956a649c9388 R15: 000000011ed82000
FS: 00007fb419959e80(0000) GS:ffff956a7aa00000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000fe6d54 CR3: 0000000138696005 CR4: 00000000003606e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
btree_submit_bio_hook+0x67/0xc0 [btrfs]
submit_one_bio+0x31/0x50 [btrfs]
btree_write_cache_pages+0x2db/0x4b0 [btrfs]
? __filemap_fdatawrite_range+0xb1/0x110
do_writepages+0x23/0x80
__filemap_fdatawrite_range+0xd2/0x110
btrfs_write_marked_extents+0x15e/0x180 [btrfs]
btrfs_sync_log+0x206/0x10a0 [btrfs]
? kmem_cache_free+0x315/0x3b0
? btrfs_log_inode+0x1e8/0xf90 [btrfs]
? __mutex_unlock_slowpath+0x45/0x2a0
? lockref_put_or_lock+0x9/0x30
? dput+0x2d/0x580
? dput+0xb5/0x580
? btrfs_sync_file+0x464/0x4d0 [btrfs]
btrfs_sync_file+0x464/0x4d0 [btrfs]
do_fsync+0x38/0x60
__x64_sys_fsync+0x10/0x20
do_syscall_64+0x5c/0x280
entry_SYSCALL_64_after_hwframe+0x49/0xbe
RIP: 0033:0x7fb41953a6d0
Code: 48 3d ...
RSP: 002b:00007ffcc86bd218 EFLAGS: 00000246 ORIG_RAX: 000000000000004a
RAX: ffffffffffffffda RBX: 000000000000000d RCX: 00007fb41953a6d0
RDX: 0000000000000009 RSI: 0000000000040000 RDI: 0000000000000003
RBP: 0000000000040000 R08: 0000000000000001 R09: 0000000000000009
R10: 0000000000000064 R11: 0000000000000246 R12: 0000556cf4b2c060
R13: 0000000000000100 R14: 0000000000000000 R15: 0000556cf322b420
irq event stamp: 0
hardirqs last enabled at (0): [<0000000000000000>] 0x0
hardirqs last disabled at (0): [<ffffffffa96bdedf>] copy_process+0x74f/0x2020
softirqs last enabled at (0): [<ffffffffa96bdedf>] copy_process+0x74f/0x2020
softirqs last disabled at (0): [<0000000000000000>] 0x0
---[ end trace d543fc76f5ad7fd8 ]---In that trace the tree checker detected the overlapping checksum items at the time when we triggered writeback for the log tree when syncing the log.
Another trace that can happen is due to BUG_ON() when deleting checksum items while logging an inode:
BTRFS critical (device dm-0): slot 81 key (18446744073709551606 128 13635584) new key (18446744073709551606 128 13635584) BTRFS info (device dm-0): leaf 30949376 gen 7 total ptrs 98 free space 8527 owner 18446744073709551610 BTRFS info (device dm-0): refs 4 lock (w:1 r:0 bw:0 br:0 sw:1 sr:0) lock_owner 13473 current 13473
item 0 key (257 1 0) itemoff 16123 itemsize 160
inode generation 7 size 262144 mode 100600
item 1 key (257 12 256) itemoff 16103 itemsize 20
item 2 key (257 108 0) itemoff 16050 itemsize 53
extent data disk bytenr 13631488 nr 4096
extent data offset 0 nr 131072 ram 131072
(...)
------------[ cut here ]------------
kernel BUG at fs/btrfs/ctree.c:3153!
invalid opcode: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC PTI
CPU: 1 PID: 13473 Comm: fsx Not tainted 5.6.0-rc7-btrfs-next-58 #1
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba5276e321-prebuilt.qemu.org 04/01/2014
RIP: 0010:btrfs_set_item_key_safe+0x1ea/0x270 [btrfs]
Code: 0f b6 ...
RSP: 0018:ffff95e3889179d0 EFLAGS: 00010282
RAX: 0000000000000000 RBX: 0000000000000051 RCX: 0000000000000000
RDX: 0000000000000000 RSI: ffffffffb7763988 RDI: 0000000000000001
RBP: fffffffffffffff6 R08: 0000000000000000 R09: 0000000000000001
R10: 00000000000009ef R11: 0000000000000000 R12: ffff8912a8ba5a08
R13: ffff95e388917a06 R14: ffff89138dcf68c8 R15: ffff95e388917ace
FS: 00007fe587084e80(0000) GS:ffff8913baa00000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007fe587091000 CR3: 0000000126dac005 CR4: 00000000003606e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
Call Trace:
btrfs_del_csums+0x2f4/0x540 [btrfs]
copy_items+0x4b5/0x560 [btrfs]
btrfs_log_inode+0x910/0xf90 [btrfs]
btrfs_log_inode_parent+0x2a0/0xe40 [btrfs]
? dget_parent+0x5/0x370
btrfs_log_dentry_safe+0x4a/0x70 [btrfs]
btrfs_sync_file+0x42b/0x4d0 [btrfs]
__x64_sys_msync+0x199/0x200
do_syscall_64+0x5c/0x280
entry_SYSCALL_64_after_hwframe+0x49/0xbe
RIP: 0033:0x7fe586c65760
Code: 00 f7 ...
RSP: 002b:00007ffe250f98b8 EFLAGS: 00000246 ORIG_RAX: 000000000000001a
RAX: ffffffffffffffda RBX: 00000000000040e1 RCX: 00007fe586c65760
RDX: 0000000000000004 RSI: 0000000000006b51 RDI: 00007fe58708b000
RBP: 0000000000006a70 R08: 0000000000000003 R09: 00007fe58700cb61
R10: 0000000000000100 R11: 0000000000000246 R12: 00000000000000e1
R13: 00007fe58708b000 R14: 0000000000006b51 R15: 0000558de021a420
Modules linked in: dm_log_writes ...
---[ end trace c92a7f447a8515f5 ]------ fs/btrfs/ctree.h | 3 +++ fs/btrfs/disk-io.c | 5 ++++- fs/btrfs/extent-io-tree.h | 1 + fs/btrfs/tree-log.c | 22 +++++++++++++++++++--- include/trace/events/btrfs.h | 1 + 5 files changed, 28 insertions(+), 4 deletions(-)
fs/btrfs/ctree.h +3 -0
@@ -1146,6 +1146,9 @@ struct btrfs_root {/* Record pairs of swapped blocks for qgroup */ struct btrfs_qgroup_swapped_blocks swapped_blocks; +/* Used only by log trees, when logging csum items */ +struct extent_io_tree log_csum_range; +#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS u64 alloc_bytenr;#endif
fs/btrfs/disk-io.c +4 -1
@@ -1137,9 +1137,12 @@ static void __setup_root(struct btrfs_ro root->log_transid =0 ; root->log_transid_committed =-1 ; root->last_log_commit =0 ; -if (!dummy) +if (!dummy) {extent_io_tree_init (fs_info, &root->dirty_log_pages,IO_TREE_ROOT_DIRTY_LOG_PAGES ,NULL ); +extent_io_tree_init (fs_info, &root->log_csum_range, +IO_TREE_LOG_CSUM_RANGE ,NULL ); + }memset (&root->root_key,0 ,sizeof (root->root_key));memset (&root->root_item,0 ,sizeof (root->root_item));
fs/btrfs/extent-io-tree.h +1 -0
@@ -44,6 +44,7 @@ enum {IO_TREE_TRANS_DIRTY_PAGES ,IO_TREE_ROOT_DIRTY_LOG_PAGES ,IO_TREE_INODE_FILE_EXTENT , +IO_TREE_LOG_CSUM_RANGE , IO_TREE_SELFTEST, };
fs/btrfs/tree-log.c +19 -3
@@ -3299,6 +3299,7 @@ static void free_log_tree(struct btrfs_tclear_extent_bits (&log->dirty_log_pages,0 , (u64)-1 ,EXTENT_DIRTY |EXTENT_NEW |EXTENT_NEED_WAIT ); +extent_io_tree_release (&log->log_csum_range);btrfs_put_root (log); }
@@ -3916,9 +3917,21 @@ static int log_csums(struct btrfs_trans_struct btrfs_root *log_root, struct btrfs_ordered_sum *sums) { + const u64 lock_end = sums->bytenr + sums->len - 1; +struct extent_state *cached_state =NULL ;int ret;/* +* Serialize logging for checksums. This is to avoid racing with the +* same checksum being logged by another task that is logging another +* file which happens to refer to the same extent as well. Such races +* can leave checksum items in the log with overlapping ranges. +*/ + ret =lock_extent_bits (&log_root->log_csum_range, sums->bytenr, + lock_end, &cached_state); +if (ret) +return ret; +/* * Due to extent cloning, we might have logged a csum item that covers a * subrange of a cloned extent, and later we can end up logging a csum * item for a larger subrange of the same extent or the entire range.
@@ -3928,10 +3941,13 @@ static int log_csums(struct btrfs_trans_* trim and adjust) any existing csum items in the log for this range. */ ret =btrfs_del_csums (trans, log_root, sums->bytenr, sums->len); -if (ret) -return ret; +if (!ret) + ret =btrfs_csum_file_blocks (trans, log_root, sums); -return btrfs_csum_file_blocks (trans, log_root, sums); +unlock_extent_cached (&log_root->log_csum_range, sums->bytenr, lock_end, + &cached_state); + +return ret; } static noinline int copy_items(struct btrfs_trans_handle *trans,
include/trace/events/btrfs.h +1 -0
@@ -89,6 +89,7 @@ TRACE_DEFINE_ENUM(COMMIT_TRANS); { IO_TREE_TRANS_DIRTY_PAGES, "TRANS_DIRTY_PAGES" }, \ { IO_TREE_ROOT_DIRTY_LOG_PAGES, "ROOT_DIRTY_LOG_PAGES" }, \ { IO_TREE_INODE_FILE_EXTENT, "INODE_FILE_EXTENT" }, \ + { IO_TREE_LOG_CSUM_RANGE, "LOG_CSUM_RANGE" }, \ { IO_TREE_SELFTEST, "SELFTEST" }) #define BTRFS_GROUP_FLAGS \
Greg Kroah-Hartman
maintainerPATCH 264/376 btrfs: fix wrong file range cleanup after an error filling dealloc range
In reply to Greg Kroah-HartmanFrom: Filipe Manana <[email protected]>
commit e2c8e92d1140754073ad3799eb6620c76bab2078 upstream.
If an error happens while running dellaloc in COW mode for a range, we can end up calling extent_clear_unlock_delalloc() for a range that goes beyond our range's end offset by 1 byte, which affects 1 extra page. This results in clearing bits and doing page operations (such as a page unlock) outside our target range.
Fix that by calling extent_clear_unlock_delalloc() with an inclusive end offset, instead of an exclusive end offset, at cow_file_range().
--- fs/btrfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/inode.c +1 -1
@@ -1142,7 +1142,7 @@ out_unlock:*/ if (extent_reserved) {extent_clear_unlock_delalloc (inode, start, - start + cur_alloc_size, + start + cur_alloc_size -1 , locked_page, clear_bits, page_ops);
Greg Kroah-Hartman
maintainerPATCH 265/376 btrfs: fix space_info bytes_may_use underflow after nocow buffered write
In reply to Greg Kroah-HartmanFrom: Filipe Manana <[email protected]>
commit 467dc47ea99c56e966e99d09dae54869850abeeb upstream.
When doing a buffered write we always try to reserve data space for it, even when the file has the NOCOW bit set or the write falls into a file range covered by a prealloc extent. This is done both because it is expensive to check if we can do a nocow write (checking if an extent is shared through reflinks or if there's a hole in the range for example), and because when writeback starts we might actually need to fallback to COW mode (for example the block group containing the target extents was turned into RO mode due to a scrub or balance).
When we are unable to reserve data space we check if we can do a nocow write, and if we can, we proceed with dirtying the pages and setting up the range for delalloc. In this case the bytes_may_use counter of the data space_info object is not incremented, unlike in the case where we are able to reserve data space (done through btrfs_check_data_free_space() which calls btrfs_alloc_data_chunk_ondemand()).
Later when running delalloc we attempt to start writeback in nocow mode but we might revert back to cow mode, for example because in the meanwhile a block group was turned into RO mode by a scrub or relocation. The cow path after successfully allocating an extent ends up calling btrfs_add_reserved_bytes(), which expects the bytes_may_use counter of the data space_info object to have been incremented before - but we did not do it when the buffered write started, since there was not enough available data space. So btrfs_add_reserved_bytes() ends up decrementing the bytes_may_use counter anyway, and when the counter's current value is smaller then the size of the allocated extent we get a stack trace like the following:
------------[ cut here ]------------ WARNING: CPU: 0 PID: 20138 at fs/btrfs/space-info.h:115 btrfs_add_reserved_bytes+0x3d6/0x4e0 [btrfs] Modules linked in: btrfs blake2b_generic xor raid6_pq libcrc32c (...) CPU: 0 PID: 20138 Comm: kworker/u8:15 Not tainted 5.6.0-rc7-btrfs-next-58 #5 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba5276e321-prebuilt.qemu.org 04/01/2014 Workqueue: writeback wb_workfn (flush-btrfs-1754) RIP: 0010:btrfs_add_reserved_bytes+0x3d6/0x4e0 [btrfs] Code: ff ff 48 (...) RSP: 0018:ffffbda18a4b3568 EFLAGS: 00010287 RAX: 0000000000000000 RBX: ffff9ca076f5d800 RCX: 0000000000000000 RDX: 0000000000000002 RSI: 0000000000000000 RDI: ffff9ca068470410 RBP: fffffffffffff000 R08: 0000000000000001 R09: 0000000000000000 R10: ffff9ca079d58040 R11: 0000000000000000 R12: ffff9ca068470400 R13: ffff9ca0408b2000 R14: 0000000000001000 R15: ffff9ca076f5d800 FS: 0000000000000000(0000) GS:ffff9ca07a600000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00005605dbfe7048 CR3: 0000000138570006 CR4: 00000000003606f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: find_free_extent+0x4a0/0x16c0 [btrfs] btrfs_reserve_extent+0x91/0x180 [btrfs] cow_file_range+0x12d/0x490 [btrfs] run_delalloc_nocow+0x341/0xa40 [btrfs] btrfs_run_delalloc_range+0x1ea/0x6d0 [btrfs] ? find_lock_delalloc_range+0x221/0x250 [btrfs] writepage_delalloc+0xe8/0x150 [btrfs] __extent_writepage+0xe8/0x4c0 [btrfs] extent_write_cache_pages+0x237/0x530 [btrfs] ? btrfs_wq_submit_bio+0x9f/0xc0 [btrfs] extent_writepages+0x44/0xa0 [btrfs] do_writepages+0x23/0x80 __writeback_single_inode+0x59/0x700 writeback_sb_inodes+0x267/0x5f0 __writeback_inodes_wb+0x87/0xe0 wb_writeback+0x382/0x590 ? wb_workfn+0x4a2/0x6c0 wb_workfn+0x4a2/0x6c0 process_one_work+0x26d/0x6a0 worker_thread+0x4f/0x3e0 ? process_one_work+0x6a0/0x6a0 kthread+0x103/0x140 ? kthread_create_worker_on_cpu+0x70/0x70 ret_from_fork+0x3a/0x50 irq event stamp: 0 hardirqs last enabled at (0): [<0000000000000000>] 0x0 hardirqs last disabled at (0): [<ffffffff94ebdedf>] copy_process+0x74f/0x2020 softirqs last enabled at (0): [<ffffffff94ebdedf>] copy_process+0x74f/0x2020 softirqs last disabled at (0): [<0000000000000000>] 0x0 ---[ end trace f9f6ef8ec4cd8ec9 ]---
So to fix this, when falling back into cow mode check if space was not reserved, by testing for the bit EXTENT_NORESERVE in the respective file range, and if not, increment the bytes_may_use counter for the data space_info object. Also clear the EXTENT_NORESERVE bit from the range, so that if the cow path fails it decrements the bytes_may_use counter when clearing the delalloc range (through the btrfs_clear_delalloc_extent() callback).
--- fs/btrfs/inode.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 56 insertions(+), 5 deletions(-)
fs/btrfs/inode.c +56 -5
@@ -49,6 +49,7 @@#include "qgroup.h" #include "delalloc-space.h" #include "block-group.h" +#include "space-info.h" struct btrfs_iget_args {struct btrfs_key *location;
@@ -1355,6 +1356,56 @@ static noinline int csum_exist_in_range(return 1 ; } +static int fallback_to_cow (struct inode *inode,struct page *locked_page, +const u64 start,const u64 end, +int *page_started,unsigned long *nr_written) +{ +struct extent_io_tree *io_tree = &BTRFS_I (inode)->io_tree; +u64 range_start = start; +u64 count; + +/* +* If EXTENT_NORESERVE is set it means that when the buffered write was +* made we had not enough available data space and therefore we did not +* reserve data space for it, since we though we could do NOCOW for the +* respective file range (either there is prealloc extent or the inode +* has the NOCOW bit set). +* +* However when we need to fallback to COW mode (because for example the +* block group for the corresponding extent was turned to RO mode by a +* scrub or relocation) we need to do the following: +* +* 1) We increment the bytes_may_use counter of the data space info. +* If COW succeeds, it allocates a new data extent and after doing +* that it decrements the space info's bytes_may_use counter and +* increments its bytes_reserved counter by the same amount (we do +* this at btrfs_add_reserved_bytes()). So we need to increment the +* bytes_may_use counter to compensate (when space is reserved at +* buffered write time, the bytes_may_use counter is incremented); +* +* 2) We clear the EXTENT_NORESERVE bit from the range. We do this so +* that if the COW path fails for any reason, it decrements (through +* extent_clear_unlock_delalloc()) the bytes_may_use counter of the +* data space info, which we incremented in the step above. +*/ + count =count_range_bits (io_tree, &range_start, end, end +1 - start, +EXTENT_NORESERVE ,0 ); +if (count >0 ) { +struct btrfs_fs_info *fs_info =BTRFS_I (inode)->root->fs_info; +struct btrfs_space_info *sinfo = fs_info->data_sinfo; + +spin_lock (&sinfo->lock); +btrfs_space_info_update_bytes_may_use (fs_info, sinfo, count); +spin_unlock (&sinfo->lock); + +clear_extent_bit (io_tree, start, end,EXTENT_NORESERVE ,0 ,0 , +NULL ); + } + +return cow_file_range (inode, locked_page, start, end, page_started, + nr_written,1 ); +} +/* * when nowcow writeback call back. This checks for snapshots or COW copies * of the extents that exist in the file, and COWs the file as required.
@@ -1602,9 +1653,9 @@ out_check:* NOCOW, following one which needs to be COW'ed */ if (cow_start != (u64)-1 ) { - ret =cow_file_range (inode, locked_page, - cow_start, found_key.offset -1 , - page_started, nr_written,1 ); + ret =fallback_to_cow (inode, locked_page, cow_start, + found_key.offset -1 , + page_started, nr_written);if (ret) {if (nocow) btrfs_dec_nocow_writers(fs_info,
@@ -1693,8 +1744,8 @@ out_check:if (cow_start != (u64)-1 ) { cur_offset = end; - ret =cow_file_range (inode, locked_page, cow_start, end, - page_started, nr_written,1 ); + ret =fallback_to_cow (inode, locked_page, cow_start, end, + page_started, nr_written);if (ret) goto error; }
Greg Kroah-Hartman
maintainerPATCH 266/376 btrfs: fix space_info bytes_may_use underflow during space cache writeout
In reply to Greg Kroah-HartmanFrom: Filipe Manana <[email protected]>
commit 2166e5edce9ac1edf3b113d6091ef72fcac2d6c4 upstream.
We always preallocate a data extent for writing a free space cache, which causes writeback to always try the nocow path first, since the free space inode has the prealloc bit set in its flags.
However if the block group that contains the data extent for the space cache has been turned to RO mode due to a running scrub or balance for example, we have to fallback to the cow path. In that case once a new data extent is allocated we end up calling btrfs_add_reserved_bytes(), which decrements the counter named bytes_may_use from the data space_info object with the expection that this counter was previously incremented with the same amount (the size of the data extent).
However when we started writeout of the space cache at cache_save_setup(), we incremented the value of the bytes_may_use counter through a call to btrfs_check_data_free_space() and then decremented it through a call to btrfs_prealloc_file_range_trans() immediately after. So when starting the writeback if we fallback to cow mode we have to increment the counter bytes_may_use of the data space_info again to compensate for the extent allocation done by the cow path.
When this issue happens we are incorrectly decrementing the bytes_may_use counter and when its current value is smaller then the amount we try to subtract we end up with the following warning:
------------[ cut here ]------------ WARNING: CPU: 3 PID: 657 at fs/btrfs/space-info.h:115 btrfs_add_reserved_bytes+0x3d6/0x4e0 [btrfs] Modules linked in: btrfs blake2b_generic xor raid6_pq libcrc32c (...) CPU: 3 PID: 657 Comm: kworker/u8:7 Tainted: G W 5.6.0-rc7-btrfs-next-58 #5 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.12.0-59-gc9ba5276e321-prebuilt.qemu.org 04/01/2014 Workqueue: writeback wb_workfn (flush-btrfs-1591) RIP: 0010:btrfs_add_reserved_bytes+0x3d6/0x4e0 [btrfs] Code: ff ff 48 (...) RSP: 0000:ffffa41608f13660 EFLAGS: 00010287 RAX: 0000000000001000 RBX: ffff9615b93ae400 RCX: 0000000000000000 RDX: 0000000000000002 RSI: 0000000000000000 RDI: ffff9615b96ab410 RBP: fffffffffffee000 R08: 0000000000000001 R09: 0000000000000000 R10: ffff961585e62a40 R11: 0000000000000000 R12: ffff9615b96ab400 R13: ffff9615a1a2a000 R14: 0000000000012000 R15: ffff9615b93ae400 FS: 0000000000000000(0000) GS:ffff9615bb200000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 000055cbbc2ae178 CR3: 0000000115794006 CR4: 00000000003606e0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 Call Trace: find_free_extent+0x4a0/0x16c0 [btrfs] btrfs_reserve_extent+0x91/0x180 [btrfs] cow_file_range+0x12d/0x490 [btrfs] btrfs_run_delalloc_range+0x9f/0x6d0 [btrfs] ? find_lock_delalloc_range+0x221/0x250 [btrfs] writepage_delalloc+0xe8/0x150 [btrfs] __extent_writepage+0xe8/0x4c0 [btrfs] extent_write_cache_pages+0x237/0x530 [btrfs] extent_writepages+0x44/0xa0 [btrfs] do_writepages+0x23/0x80 __writeback_single_inode+0x59/0x700 writeback_sb_inodes+0x267/0x5f0 __writeback_inodes_wb+0x87/0xe0 wb_writeback+0x382/0x590 ? wb_workfn+0x4a2/0x6c0 wb_workfn+0x4a2/0x6c0 process_one_work+0x26d/0x6a0 worker_thread+0x4f/0x3e0 ? process_one_work+0x6a0/0x6a0 kthread+0x103/0x140 ? kthread_create_worker_on_cpu+0x70/0x70 ret_from_fork+0x3a/0x50 irq event stamp: 0 hardirqs last enabled at (0): [<0000000000000000>] 0x0 hardirqs last disabled at (0): [<ffffffffb2abdedf>] copy_process+0x74f/0x2020 softirqs last enabled at (0): [<ffffffffb2abdedf>] copy_process+0x74f/0x2020 softirqs last disabled at (0): [<0000000000000000>] 0x0 ---[ end trace bd7c03622e0b0a52 ]--- ------------[ cut here ]------------
So fix this by incrementing the bytes_may_use counter of the data space_info when we fallback to the cow path. If the cow path is successful the counter is decremented after extent allocation (by btrfs_add_reserved_bytes()), if it fails it ends up being decremented as well when clearing the delalloc range (extent_clear_unlock_delalloc()).
This could be triggered sporadically by the test case btrfs/061 from fstests.
--- fs/btrfs/inode.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-)
fs/btrfs/inode.c +15 -5
@@ -1360,6 +1360,8 @@ static int fallback_to_cow(struct inode const u64 start, const u64 end, int *page_started, unsigned long *nr_written) { + const bool is_space_ino = btrfs_is_free_space_inode(BTRFS_I(inode)); +const u64 range_bytes = end +1 - start;struct extent_io_tree *io_tree = &BTRFS_I (inode)->io_tree;u64 range_start = start;u64 count;
@@ -1387,19 +1389,27 @@ static int fallback_to_cow(struct inode* that if the COW path fails for any reason, it decrements (through * extent_clear_unlock_delalloc()) the bytes_may_use counter of the * data space info, which we incremented in the step above. +* +* If we need to fallback to cow and the inode corresponds to a free +* space cache inode, we must also increment bytes_may_use of the data +* space_info for the same reason. Space caches always get a prealloc +* extent for them, however scrub or balance may have set the block +* group that contains that extent to RO mode. */ - count =count_range_bits (io_tree, &range_start, end, end +1 - start, + count =count_range_bits (io_tree, &range_start, end, range_bytes,EXTENT_NORESERVE ,0 ); -if (count >0 ) { +if (count >0 || is_space_ino) { +const u64 bytes = is_space_ino ? range_bytes : count;struct btrfs_fs_info *fs_info =BTRFS_I (inode)->root->fs_info;struct btrfs_space_info *sinfo = fs_info->data_sinfo;spin_lock (&sinfo->lock); -btrfs_space_info_update_bytes_may_use (fs_info, sinfo, count); +btrfs_space_info_update_bytes_may_use (fs_info, sinfo, bytes);spin_unlock (&sinfo->lock); -clear_extent_bit (io_tree, start, end,EXTENT_NORESERVE ,0 ,0 , -NULL ); +if (count >0 ) +clear_extent_bit (io_tree, start, end,EXTENT_NORESERVE , +0 ,0 ,NULL ); } return cow_file_range(inode, locked_page, start, end, page_started,
Greg Kroah-Hartman
maintainerPATCH 267/376 powerpc/mm: Fix conditions to perform MMU specific management by blocks on PPC32.
In reply to Greg Kroah-HartmanFrom: Christophe Leroy <[email protected]>
commit 4e3319c23a66dabfd6c35f4d2633d64d99b68096 upstream.
Setting init mem to NX shall depend on sinittext being mapped by block, not on stext being mapped by block.
Setting text and rodata to RO shall depend on stext being mapped by block, not on sinittext being mapped by block.
--- arch/powerpc/mm/pgtable_32.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/powerpc/mm/pgtable_32.c +2 -2
@@ -169,7 +169,7 @@ void mark_initmem_nx(void)unsigned long numpages =PFN_UP ((unsigned long )_einittext) -PFN_DOWN ((unsigned long )_sinittext); -if (v_block_mapped ((unsigned long )_stext +1 )) +if (v_block_mapped ((unsigned long )_sinittext))mmu_mark_initmem_nx ();else change_page_attr (page, numpages,PAGE_KERNEL );
@@ -181,7 +181,7 @@ void mark_rodata_ro(void)struct page *page;unsigned long numpages; -if (v_block_mapped ((unsigned long )_sinittext)) { +if (v_block_mapped ((unsigned long )_stext +1 )) {mmu_mark_rodata_ro ();ptdump_check_wx ();return ;
Greg Kroah-Hartman
maintainerPATCH 268/376 mm: thp: make the THP mapcount atomic against __split_huge_pmd_locked()
In reply to Greg Kroah-HartmanFrom: Andrea Arcangeli <[email protected]>
commit c444eb564fb16645c172d550359cb3d75fe8a040 upstream.
Write protect anon page faults require an accurate mapcount to decide if to break the COW or not. This is implemented in the THP path with reuse_swap_page() -> page_trans_huge_map_swapcount()/page_trans_huge_mapcount().
If the COW triggers while the other processes sharing the page are under a huge pmd split, to do an accurate reading, we must ensure the mapcount isn't computed while it's being transferred from the head page to the tail pages.
reuse_swap_cache() already runs serialized by the page lock, so it's enough to add the page lock around __split_huge_pmd_locked too, in order to add the missing serialization.
Note: the commit in "Fixes" is just to facilitate the backporting, because the code before such commit didn't try to do an accurate THP mapcount calculation and it instead used the page_count() to decide if to COW or not. Both the page_count and the pin_count are THP-wide refcounts, so they're inaccurate if used in reuse_swap_page(). Reverting such commit (besides the unrelated fix to the local anon_vma assignment) would have also opened the window for memory corruption side effects to certain workloads as documented in such commit header.
--- mm/huge_memory.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-)
mm/huge_memory.c +28 -3
@@ -2385,6 +2385,8 @@ void __split_huge_pmd(struct vm_area_str {spinlock_t *ptl;struct mmu_notifier_range range; +bool was_locked = false; +pmd_t _pmd; mmu_notifier_range_init(&range, MMU_NOTIFY_CLEAR, 0, vma, vma->vm_mm, address & HPAGE_PMD_MASK,
@@ -2397,11 +2399,32 @@ void __split_huge_pmd(struct vm_area_str* pmd against. Otherwise we can end up replacing wrong page. */ VM_BUG_ON (freeze && !page); -if (page && page !=pmd_page (*pmd)) - goto out; +if (page) { +VM_WARN_ON_ONCE (!PageLocked (page)); + was_locked = true; +if (page !=pmd_page (*pmd)) + goto out; + } +repeat:if (pmd_trans_huge (*pmd)) { - page =pmd_page (*pmd); +if (!page) { + page =pmd_page (*pmd); +if (unlikely (!trylock_page (page))) { +get_page (page); + _pmd = *pmd; +spin_unlock (ptl); +lock_page (page); +spin_lock (ptl); +if (unlikely (!pmd_same (*pmd, _pmd))) { +unlock_page (page); +put_page (page); + page =NULL ; + goto repeat; + } +put_page (page); + } + }if (PageMlocked (page))clear_page_mlock (page); }else if (!(pmd_devmap (*pmd) ||is_pmd_migration_entry (*pmd)))
@@ -2409,6 +2432,8 @@ void __split_huge_pmd(struct vm_area_str__split_huge_pmd_locked (vma, pmd, range.start, freeze); out:spin_unlock (ptl); +if (!was_locked && page) +unlock_page (page);/* * No need to double call mmu_notifier->invalidate_range() callback. * They are 3 cases to consider inside __split_huge_pmd_locked():
Greg Kroah-Hartman
maintainerPATCH 269/376 mm: initialize deferred pages with interrupts enabled
In reply to Greg Kroah-HartmanFrom: Pavel Tatashin <[email protected]>
commit 3d060856adfc59afb9d029c233141334cfaba418 upstream.
Initializing struct pages is a long task and keeping interrupts disabled for the duration of this operation introduces a number of problems.
1. jiffies are not updated for long period of time, and thus incorrect time is reported. See proposed solution and discussion here:
lkml/[email protected]
2. It prevents farther improving deferred page initialization by allowing intra-node multi-threading.
We are keeping interrupts disabled to solve a rather theoretical problem that was never observed in real world (See 3a2d7fa8a3d5).
Let's keep interrupts enabled. In case we ever encounter a scenario where an interrupt thread wants to allocate large amount of memory this early in boot we can deal with that by growing zone (see deferred_grow_zone()) by the needed amount before starting deferred_init_memmap() threads.
Before:
[ 1.232459] node 0 initialised, 12058412 pages in 1ms
After:
[ 1.632580] node 0 initialised, 12051227 pages in 436ms
--- include/linux/mmzone.h | 2 ++ mm/page_alloc.c | 20 +++++++------------- 2 files changed, 9 insertions(+), 13 deletions(-)
include/linux/mmzone.h +2 -0
@@ -678,6 +678,8 @@ typedef struct pglist_data {/* * Must be held any time you expect node_start_pfn, * node_present_pages, node_spanned_pages or nr_zones to stay constant. +* Also synchronizes pgdat->first_deferred_pfn during deferred page +* init. * * pgdat_resize_lock() and pgdat_resize_unlock() are provided to * manipulate node_size_lock without checking for CONFIG_MEMORY_HOTPLUG
mm/page_alloc.c +7 -13
@@ -1845,6 +1845,13 @@ static int __init deferred_init_memmap(vBUG_ON (pgdat->first_deferred_pfn >pgdat_end_pfn (pgdat)); pgdat->first_deferred_pfn =ULONG_MAX ; +/* +* Once we unlock here, the zone cannot be grown anymore, thus if an +* interrupt thread must allocate this early in boot, zone must be +* pre-grown prior to start of deferred page initialization. +*/ +pgdat_resize_unlock (pgdat, &flags); +/* Only the highest zone is deferred so find it */ for (zid =0 ; zid <MAX_NR_ZONES ; zid++) { zone = pgdat->node_zones + zid;
@@ -1865,8 +1872,6 @@ static int __init deferred_init_memmap(vwhile (spfn < epfn) nr_pages +=deferred_init_maxorder (&i, zone, &spfn, &epfn); zone_empty: -pgdat_resize_unlock (pgdat, &flags); -/* Sanity check that the next zone really is unpopulated */ WARN_ON (++zid <MAX_NR_ZONES &&populated_zone (++zone));
@@ -1909,17 +1914,6 @@ deferred_grow_zone(struct zone *zone, unpgdat_resize_lock (pgdat, &flags);/* -* If deferred pages have been initialized while we were waiting for -* the lock, return true, as the zone was grown. The caller will retry -* this zone. We won't return to this function since the caller also -* has this static branch. -*/ -if (!static_branch_unlikely (&deferred_pages)) { -pgdat_resize_unlock (pgdat, &flags); -return true; - } - -/* * If someone grew this zone while we were waiting for spinlock, return * true, as there might be enough pages already. */
Greg Kroah-Hartman
maintainerPATCH 270/376 MIPS: CPU_LOONGSON2EF need software to maintain cache consistency
In reply to Greg Kroah-HartmanFrom: Lichao Liu <[email protected]>
commit a202bf71f08b3ef15356db30535e30b03cf23aec upstream.
CPU_LOONGSON2EF need software to maintain cache consistency, so modify the 'cpu_needs_post_dma_flush' function to return true when the cpu type is CPU_LOONGSON2EF.
--- arch/mips/mm/dma-noncoherent.c | 1 + 1 file changed, 1 insertion(+)
arch/mips/mm/dma-noncoherent.c +1 -0
@@ -33,6 +33,7 @@ static inline bool cpu_needs_post_dma_flcase CPU_R10000 :case CPU_R12000 :case CPU_BMIPS5000 : +case CPU_LOONGSON2EF :return true;default :/*
Greg Kroah-Hartman
maintainerPATCH 271/376 mm/pagealloc.c: call touch_nmi_watchdog() on max order boundaries in deferred init
In reply to Greg Kroah-HartmanFrom: Daniel Jordan <[email protected]>
commit 117003c32771df617acf66e140fbdbdeb0ac71f5 upstream.
Patch series "initialize deferred pages with interrupts enabled", v4.
Keep interrupts enabled during deferred page initialization in order to make code more modular and allow jiffies to update.
Original approach, and discussion can be found here:
http://lkml.kernel.org/r/[email protected]
This patch (of 3):
deferred_init_memmap() disables interrupts the entire time, so it calls touch_nmi_watchdog() periodically to avoid soft lockup splats. Soon it will run with interrupts enabled, at which point cond_resched() should be used instead.
deferred_grow_zone() makes the same watchdog calls through code shared with deferred init but will continue to run with interrupts disabled, so it can't call cond_resched().
Pull the watchdog calls up to these two places to allow the first to be changed later, independently of the second. The frequency reduces from twice per pageblock (init and free) to once per max order block.
--- mm/page_alloc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
mm/page_alloc.c +4 -3
@@ -1692,7 +1692,6 @@ static void __init deferred_free_pages(u }else if (!(pfn & nr_pgmask)) {deferred_free_range (pfn - nr_free, nr_free); nr_free =1 ; -touch_nmi_watchdog (); }else { nr_free++; }
@@ -1722,7 +1721,6 @@ static unsigned long __init deferred_incontinue ; }else if (!page || !(pfn & nr_pgmask)) { page =pfn_to_page (pfn); -touch_nmi_watchdog (); }else { page++; }
@@ -1869,8 +1867,10 @@ static int __init deferred_init_memmap(v* that we can avoid introducing any issues with the buddy * allocator. */ -while (spfn < epfn) +while (spfn < epfn) { nr_pages +=deferred_init_maxorder (&i, zone, &spfn, &epfn); +touch_nmi_watchdog (); + } zone_empty:/* Sanity check that the next zone really is unpopulated */ WARN_ON (++zid <MAX_NR_ZONES &&populated_zone (++zone));
@@ -1941,6 +1941,7 @@ deferred_grow_zone(struct zone *zone, un first_deferred_pfn = spfn; nr_pages +=deferred_init_maxorder (&i, zone, &spfn, &epfn); +touch_nmi_watchdog ();/* We should only stop along section boundaries */ if ((first_deferred_pfn ^ spfn) <PAGES_PER_SECTION )
Greg Kroah-Hartman
maintainerPATCH 272/376 mm: call cond_resched() from deferred_init_memmap()
In reply to Greg Kroah-HartmanFrom: Pavel Tatashin <[email protected]>
commit da97f2d56bbd880b4138916a7ef96f9881a551b2 upstream.
Now that deferred pages are initialized with interrupts enabled we can replace touch_nmi_watchdog() with cond_resched(), as it was before 3a2d7fa8a3d5.
For now, we cannot do the same in deferred_grow_zone() as it is still initializes pages with interrupts disabled.
This change fixes RCU problem described in
https://lkml.kernel.org/r/[email protected]
[ 60.474005] rcu: INFO: rcu_sched detected stalls on CPUs/tasks: [ 60.475000] rcu: 1-...0: (0 ticks this GP) idle=02a/1/0x4000000000000000 softirq=1/1 fqs=15000 [ 60.475000] rcu: (detected by 0, t=60002 jiffies, g=-1199, q=1) [ 60.475000] Sending NMI from CPU 0 to CPUs 1: [ 1.760091] NMI backtrace for cpu 1 [ 1.760091] CPU: 1 PID: 20 Comm: pgdatinit0 Not tainted 4.18.0-147.9.1.el8_1.x86_64 #1 [ 1.760091] Hardware name: Red Hat KVM, BIOS 1.13.0-1.module+el8.2.0+5520+4e5817f3 04/01/2014 [ 1.760091] RIP: 0010:__init_single_page.isra.65+0x10/0x4f [ 1.760091] Code: 48 83 cf 63 48 89 f8 0f 1f 40 00 48 89 c6 48 89 d7 e8 6b 18 80 ff 66 90 5b c3 31 c0 b9 10 00 00 00 49 89 f8 48 c1 e6 33 f3 ab <b8> 07 00 00 00 48 c1 e2 36 41 c7 40 34 01 00 00 00 48 c1 e0 33 41 [ 1.760091] RSP: 0000:ffffba783123be40 EFLAGS: 00000006 [ 1.760091] RAX: 0000000000000000 RBX: fffffad34405e300 RCX: 0000000000000000 [ 1.760091] RDX: 0000000000000000 RSI: 0010000000000000 RDI: fffffad34405e340 [ 1.760091] RBP: 0000000033f3177e R08: fffffad34405e300 R09: 0000000000000002 [ 1.760091] R10: 000000000000002b R11: ffff98afb691a500 R12: 0000000000000002 [ 1.760091] R13: 0000000000000000 R14: 000000003f03ea00 R15: 000000003e10178c [ 1.760091] FS: 0000000000000000(0000) GS:ffff9c9ebeb00000(0000) knlGS:0000000000000000 [ 1.760091] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 1.760091] CR2: 00000000ffffffff CR3: 000000a1cf20a001 CR4: 00000000003606e0 [ 1.760091] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 1.760091] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 1.760091] Call Trace: [ 1.760091] deferred_init_pages+0x8f/0xbf [ 1.760091] deferred_init_memmap+0x184/0x29d [ 1.760091] ? deferred_free_pages.isra.97+0xba/0xba [ 1.760091] kthread+0x112/0x130 [ 1.760091] ? kthread_flush_work_fn+0x10/0x10 [ 1.760091] ret_from_fork+0x35/0x40 [ 89.123011] node 0 initialised, 1055935372 pages in 88650ms
--- mm/page_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/page_alloc.c +1 -1
@@ -1869,7 +1869,7 @@ static int __init deferred_init_memmap(v*/ while (spfn < epfn) { nr_pages +=deferred_init_maxorder (&i, zone, &spfn, &epfn); -touch_nmi_watchdog (); +cond_resched (); } zone_empty:/* Sanity check that the next zone really is unpopulated */
Greg Kroah-Hartman
maintainerPATCH 273/376 ima: Fix ima digest hash table key calculation
In reply to Greg Kroah-HartmanFrom: Krzysztof Struczynski <[email protected]>
commit 1129d31b55d509f15e72dc68e4b5c3a4d7b4da8d upstream.
Function hash_long() accepts unsigned long, while currently only one byte is passed from ima_hash_key(), which calculates a key for ima_htable.
Given that hashing the digest does not give clear benefits compared to using the digest itself, remove hash_long() and return the modulus calculated on the first two bytes of the digest with the number of slots. Also reduce the depth of the hash table by doubling the number of slots.
--- security/integrity/ima/ima.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
security/integrity/ima/ima.h +4 -3
@@ -36,7 +36,7 @@ enum tpm_pcrs { TPM_PCR0 = 0, TPM_PCR8 =#define IMA_DIGEST_SIZE SHA1_DIGEST_SIZE#define IMA_EVENT_NAME_LEN_MAX 255 -#define IMA_HASH_BITS 9 +#define IMA_HASH_BITS 10#define IMA_MEASURE_HTABLE_SIZE (1 << IMA_HASH_BITS)#define IMA_TEMPLATE_FIELD_ID_MAX_LEN 16
@@ -175,9 +175,10 @@ struct ima_h_table { };extern struct ima_h_table ima_htable; -static inline unsigned long ima_hash_key (u8 *digest) +static inline unsigned int ima_hash_key (u8 *digest) { -return hash_long (*digest,IMA_HASH_BITS ); +/* there is no point in taking a hash of part of a digest */ +return (digest[0 ] | digest[1 ] <<8 ) %IMA_MEASURE_HTABLE_SIZE ; }#define __ima_hooks (hook) \
Greg Kroah-Hartman
maintainerPATCH 274/376 ima: Switch to ima_hash_algo for boot aggregate
In reply to Greg Kroah-HartmanFrom: Roberto Sassu <[email protected]>
commit 6f1a1d103b48b1533a9c804e7a069e2c8e937ce7 upstream.
boot_aggregate is the first entry of IMA measurement list. Its purpose is to link pre-boot measurements to IMA measurements. As IMA was designed to work with a TPM 1.2, the SHA1 PCR bank was always selected even if a TPM 2.0 with support for stronger hash algorithms is available.
This patch first tries to find a PCR bank with the IMA default hash algorithm. If it does not find it, it selects the SHA256 PCR bank for TPM 2.0 and SHA1 for TPM 1.2. Ultimately, it selects SHA1 also for TPM 2.0 if the SHA256 PCR bank is not found.
If none of the PCR banks above can be found, boot_aggregate file digest is filled with zeros, as for TPM bypass, making it impossible to perform a remote attestation of the system.
--- security/integrity/ima/ima_crypto.c | 47 +++++++++++++++++++++++++++++++----- security/integrity/ima/ima_init.c | 20 ++++++++++++--- 2 files changed, 57 insertions(+), 10 deletions(-)
security/integrity/ima/ima_crypto.c +41 -6
@@ -655,18 +655,29 @@ static void __init ima_pcrread(u32 idx, }/* -* Calculate the boot aggregate hash +* The boot_aggregate is a cumulative hash over TPM registers 0 - 7. With +* TPM 1.2 the boot_aggregate was based on reading the SHA1 PCRs, but with +* TPM 2.0 hash agility, TPM chips could support multiple TPM PCR banks, +* allowing firmware to configure and enable different banks. +* +* Knowing which TPM bank is read to calculate the boot_aggregate digest +* needs to be conveyed to a verifier. For this reason, use the same +* hash algorithm for reading the TPM PCRs as for calculating the boot +* aggregate digest as stored in the measurement list. */ -static int __init ima_calc_boot_aggregate_tfm (char *digest, +static int __init ima_calc_boot_aggregate_tfm (char *digest,u16 alg_id,struct crypto_shash *tfm) { -struct tpm_digest d = { .alg_id =TPM_ALG_SHA1 , .digest = {0 } }; +struct tpm_digest d = { .alg_id = alg_id, .digest = {0 } };int rc;u32 i;SHASH_DESC_ON_STACK (shash, tfm); shash->tfm = tfm; +pr_devel ("calculating the boot-aggregate based on TPM bank: %04x\n" , + d.alg_id); + rc =crypto_shash_init (shash);if (rc !=0 )return rc;
@@ -675,7 +686,8 @@ static int __init ima_calc_boot_aggregatfor (i =TPM_PCR0 ; i <TPM_PCR8 ; i++) {ima_pcrread (i, &d);/* now accumulate with current aggregate */ - rc =crypto_shash_update (shash, d.digest,TPM_DIGEST_SIZE ); + rc =crypto_shash_update (shash, d.digest, +crypto_shash_digestsize (tfm)); }if (!rc)crypto_shash_final (shash, digest);
@@ -685,14 +697,37 @@ static int __init ima_calc_boot_aggregatint __init ima_calc_boot_aggregate (struct ima_digest_data *hash) {struct crypto_shash *tfm; -int rc; +u16 crypto_id, alg_id; +int rc, i, bank_idx =-1 ; + +for (i =0 ; i < ima_tpm_chip->nr_allocated_banks; i++) { + crypto_id = ima_tpm_chip->allocated_banks[i].crypto_id; +if (crypto_id == hash->algo) { + bank_idx = i; +break ; + } + +if (crypto_id ==HASH_ALGO_SHA256 ) + bank_idx = i; + +if (bank_idx ==-1 && crypto_id ==HASH_ALGO_SHA1 ) + bank_idx = i; + } + +if (bank_idx ==-1 ) { +pr_err ("No suitable TPM algorithm for boot aggregate\n" ); +return 0 ; + } + + hash->algo = ima_tpm_chip->allocated_banks[bank_idx].crypto_id; tfm =ima_alloc_tfm (hash->algo);if (IS_ERR (tfm))return PTR_ERR (tfm); hash->length =crypto_shash_digestsize (tfm); - rc =ima_calc_boot_aggregate_tfm (hash->digest, tfm); + alg_id = ima_tpm_chip->allocated_banks[bank_idx].alg_id; + rc =ima_calc_boot_aggregate_tfm (hash->digest, alg_id, tfm);ima_free_tfm (tfm);
security/integrity/ima/ima_init.c +16 -4
@@ -25,7 +25,7 @@ struct tpm_chip *ima_tpm_chip;/* Add the boot aggregate to the IMA measurement list and extend * the PCR register. * -* Calculate the boot aggregate, a SHA1 over tpm registers 0-7, +* Calculate the boot aggregate, a hash over tpm registers 0-7, * assuming a TPM chip exists, and zeroes if the TPM chip does not * exist. Add the boot aggregate measurement to the measurement * list and extend the PCR register.
@@ -49,15 +49,27 @@ static int __init ima_add_boot_aggregateint violation =0 ;struct {struct ima_digest_data hdr; -char digest[TPM_DIGEST_SIZE ]; +char digest[TPM_MAX_DIGEST_SIZE ]; } hash;memset (iint,0 ,sizeof (*iint));memset (&hash,0 ,sizeof (hash)); iint->ima_hash = &hash.hdr; - iint->ima_hash->algo =HASH_ALGO_SHA1 ; - iint->ima_hash->length =SHA1_DIGEST_SIZE ; + iint->ima_hash->algo = ima_hash_algo; + iint->ima_hash->length = hash_digest_size[ima_hash_algo]; +/* +* With TPM 2.0 hash agility, TPM chips could support multiple TPM +* PCR banks, allowing firmware to configure and enable different +* banks. The SHA1 bank is not necessarily enabled. +* +* Use the same hash algorithm for reading the TPM PCRs as for +* calculating the boot aggregate digest. Preference is given to +* the configured IMA default hash algorithm. Otherwise, use the +* TCG required banks - SHA256 for TPM 2.0, SHA1 for TPM 1.2. +* Ultimately select SHA1 also for TPM 2.0 if the SHA256 PCR bank +* is not found. +*/ if (ima_tpm_chip) { result =ima_calc_boot_aggregate (&hash.hdr);if (result <0 ) {
Greg Kroah-Hartman
maintainerPATCH 275/376 ima: Evaluate error in init_ima()
In reply to Greg Kroah-HartmanFrom: Roberto Sassu <[email protected]>
commit e144d6b265415ddbdc54b3f17f4f95133effa5a8 upstream.
Evaluate error in init_ima() before register_blocking_lsm_notifier() and return if not zero.
--- security/integrity/ima/ima_main.c | 3 +++ 1 file changed, 3 insertions(+)
security/integrity/ima/ima_main.c +3 -0
@@ -792,6 +792,9 @@ static int __init init_ima(void) error =ima_init (); } +if (error) +return error; + error =register_blocking_lsm_notifier (&ima_lsm_policy_notifier);if (error)pr_warn ("Couldn't register LSM notifier, error %d\n" , error);
Greg Kroah-Hartman
maintainerPATCH 276/376 ima: Directly assign the ima_default_policy pointer to ima_rules
In reply to Greg Kroah-HartmanFrom: Roberto Sassu <[email protected]>
commit 067a436b1b0aafa593344fddd711a755a58afb3b upstream.
This patch prevents the following oops:
[ 10.771813] BUG: kernel NULL pointer dereference, address: 0000000000000 [...] [ 10.779790] RIP: 0010:ima_match_policy+0xf7/0xb80 [...] [ 10.798576] Call Trace: [ 10.798993] ? ima_lsm_policy_change+0x2b0/0x2b0 [ 10.799753] ? inode_init_owner+0x1a0/0x1a0 [ 10.800484] ? _raw_spin_lock+0x7a/0xd0 [ 10.801592] ima_must_appraise.part.0+0xb6/0xf0 [ 10.802313] ? ima_fix_xattr.isra.0+0xd0/0xd0 [ 10.803167] ima_must_appraise+0x4f/0x70 [ 10.804004] ima_post_path_mknod+0x2e/0x80 [ 10.804800] do_mknodat+0x396/0x3c0
It occurs when there is a failure during IMA initialization, and ima_init_policy() is not called. IMA hooks still call ima_match_policy() but ima_rules is NULL. This patch prevents the crash by directly assigning the ima_default_policy pointer to ima_rules when ima_rules is defined. This wouldn't alter the existing behavior, as ima_rules is always set at the end of ima_init_policy().
--- security/integrity/ima/ima_policy.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
security/integrity/ima/ima_policy.c +1 -2
@@ -204,7 +204,7 @@ static struct ima_rule_entry *arch_policstatic LIST_HEAD (ima_default_rules);static LIST_HEAD (ima_policy_rules);static LIST_HEAD (ima_temp_rules); -static struct list_head *ima_rules; +static struct list_head *ima_rules = &ima_default_rules;/* Pre-allocated buffer used for matching keyrings. */ static char *ima_keyrings;
@@ -765,7 +765,6 @@ void __init ima_init_policy(void)ARRAY_SIZE (default_appraise_rules), IMA_DEFAULT_POLICY); - ima_rules = &ima_default_rules;ima_update_policy_flag (); }
Greg Kroah-Hartman
maintainerPATCH 277/376 ima: Call ima_calc_boot_aggregate() in ima_eventdigest_init()
In reply to Greg Kroah-HartmanFrom: Roberto Sassu <[email protected]>
commit 6cc7c266e5b47d3cd2b5bb7fd3aac4e6bb2dd1d2 upstream.
If the template field 'd' is chosen and the digest to be added to the measurement entry was not calculated with SHA1 or MD5, it is recalculated with SHA1, by using the passed file descriptor. However, this cannot be done for boot_aggregate, because there is no file descriptor.
This patch adds a call to ima_calc_boot_aggregate() in ima_eventdigest_init(), so that the digest can be recalculated also for the boot_aggregate entry.
--- security/integrity/ima/ima.h | 3 ++- security/integrity/ima/ima_crypto.c | 6 +++--- security/integrity/ima/ima_init.c | 2 +- security/integrity/ima/ima_template_lib.c | 18 ++++++++++++++++++ 4 files changed, 24 insertions(+), 5 deletions(-)
security/integrity/ima/ima.h +2 -1
@@ -52,6 +52,7 @@ extern int ima_policy_flag;extern int ima_hash_algo;extern int ima_appraise;extern struct tpm_chip *ima_tpm_chip; +extern const char boot_aggregate_name[];/* IMA event related data */ struct ima_event_data {
@@ -140,7 +141,7 @@ int ima_calc_buffer_hash(const void *bufint ima_calc_field_array_hash (struct ima_field_data *field_data,struct ima_template_desc *desc,int num_fields,struct ima_digest_data *hash); -int __init ima_calc_boot_aggregate (struct ima_digest_data *hash); +int ima_calc_boot_aggregate (struct ima_digest_data *hash);void ima_add_violation (struct file *file,const unsigned char *filename,struct integrity_iint_cache *iint,const char *op,const char *cause);
security/integrity/ima/ima_crypto.c +3 -3
@@ -665,8 +665,8 @@ static void __init ima_pcrread(u32 idx,* hash algorithm for reading the TPM PCRs as for calculating the boot * aggregate digest as stored in the measurement list. */ -static int __init ima_calc_boot_aggregate_tfm (char *digest,u16 alg_id, -struct crypto_shash *tfm) +static int ima_calc_boot_aggregate_tfm (char *digest,u16 alg_id, +struct crypto_shash *tfm) {struct tpm_digest d = { .alg_id = alg_id, .digest = {0 } };int rc;
@@ -694,7 +694,7 @@ static int __init ima_calc_boot_aggregatreturn rc; } -int __init ima_calc_boot_aggregate (struct ima_digest_data *hash) +int ima_calc_boot_aggregate (struct ima_digest_data *hash) {struct crypto_shash *tfm;u16 crypto_id, alg_id;
security/integrity/ima/ima_init.c +1 -1
@@ -19,7 +19,7 @@#include "ima.h" /* name for boot aggregate entry */ -static const char boot_aggregate_name[] ="boot_aggregate" ; +const char boot_aggregate_name[] ="boot_aggregate" ;struct tpm_chip *ima_tpm_chip;/* Add the boot aggregate to the IMA measurement list and extend
security/integrity/ima/ima_template_lib.c +18 -0
@@ -286,6 +286,24 @@ int ima_eventdigest_init(struct ima_even goto out; } +if ((const char *)event_data->filename == boot_aggregate_name) { +if (ima_tpm_chip) { + hash.hdr.algo =HASH_ALGO_SHA1 ; + result =ima_calc_boot_aggregate (&hash.hdr); + +/* algo can change depending on available PCR banks */ +if (!result && hash.hdr.algo !=HASH_ALGO_SHA1 ) + result = -EINVAL ; + +if (result <0 ) +memset (&hash,0 ,sizeof (hash)); + } + + cur_digest = hash.hdr.digest; + cur_digestsize = hash_digest_size[HASH_ALGO_SHA1 ]; + goto out; + } +if (!event_data->file)/* missing info to re-calculate the digest */ return -EINVAL ;
Greg Kroah-Hartman
maintainerPATCH 278/376 ima: Remove __init annotation from ima_pcrread()
In reply to Greg Kroah-HartmanFrom: Roberto Sassu <[email protected]>
commit 8b8c704d913b0fe490af370631a4200e26334ec0 upstream.
Commit 6cc7c266e5b4 ("ima: Call ima_calc_boot_aggregate() in ima_eventdigest_init()") added a call to ima_calc_boot_aggregate() so that the digest can be recalculated for the boot_aggregate measurement entry if the 'd' template field has been requested. For the 'd' field, only SHA1 and MD5 digests are accepted.
Given that ima_eventdigest_init() does not have the __init annotation, all functions called should not have it. This patch removes __init from ima_pcrread().
--- security/integrity/ima/ima_crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
security/integrity/ima/ima_crypto.c +1 -1
@@ -645,7 +645,7 @@ int ima_calc_buffer_hash(const void *bufreturn calc_buffer_shash (buf, len, hash); } -static void __init ima_pcrread (u32 idx,struct tpm_digest *d) +static void ima_pcrread (u32 idx,struct tpm_digest *d) {if (!ima_tpm_chip)return ;
Greg Kroah-Hartman
maintainerPATCH 279/376 evm: Fix possible memory leak in evm_calc_hmac_or_hash()
In reply to Greg Kroah-HartmanFrom: Roberto Sassu <[email protected]>
commit 0c4395fb2aa77341269ea619c5419ea48171883f upstream.
Don't immediately return if the signature is portable and security.ima is not present. Just set error so that memory allocated is freed before returning from evm_calc_hmac_or_hash().
--- security/integrity/evm/evm_crypto.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
security/integrity/evm/evm_crypto.c +1 -1
@@ -241,7 +241,7 @@ static int evm_calc_hmac_or_hash(struct/* Portable EVM signatures must include an IMA hash */ if (type ==EVM_XATTR_PORTABLE_DIGSIG && !ima_present) -return -EPERM ; + error = -EPERM ; out:kfree (xattr_value);kfree (desc);
Greg Kroah-Hartman
maintainerPATCH 280/376 ext4: fix EXT_MAX_EXTENT/INDEX to check for zeroed eh_max
In reply to Greg Kroah-HartmanFrom: Harshad Shirwadkar <[email protected]>
commit c36a71b4e35ab35340facdd6964a00956b9fef0a upstream.
If eh->eh_max is 0, EXT_MAX_EXTENT/INDEX would evaluate to unsigned (-1) resulting in illegal memory accesses. Although there is no consistent repro, we see that generic/019 sometimes crashes because of this bug.
Ran gce-xfstests smoke and verified that there were no regressions.
--- fs/ext4/ext4_extents.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
fs/ext4/ext4_extents.h +6 -3
@@ -170,10 +170,13 @@ struct partial_cluster { (EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1)#define EXT_LAST_INDEX (__hdr__) \ (EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1) -#define EXT_MAX_EXTENT (__hdr__) \ - (EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1) +#define EXT_MAX_EXTENT (__hdr__) \ + ((le16_to_cpu((__hdr__)->eh_max)) ? \ + ((EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)) \ + : 0)#define EXT_MAX_INDEX (__hdr__) \ - (EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1) + ((le16_to_cpu((__hdr__)->eh_max)) ? \ + ((EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)) : 0)static inline struct ext4_extent_header *ext_inode_hdr (struct inode *inode) {
Greg Kroah-Hartman
maintainerPATCH 281/376 ext4: fix buffer_head refcnt leak when ext4_iget() fails
In reply to Greg Kroah-HartmanFrom: Xiyu Yang <[email protected]>
commit 3bbd0ef26098d241dc59ee77ba14b7dab0df0786 upstream.
ext4_orphan_get() invokes ext4_read_inode_bitmap(), which returns a reference of the specified buffer_head object to "bitmap_bh" with increased refcnt.
When ext4_orphan_get() returns, local variable "bitmap_bh" becomes invalid, so the refcount should be decreased to keep refcount balanced.
The reference counting issue happens in one exception handling path of ext4_orphan_get(). When ext4_iget() fails, the function forgets to decrease the refcnt increased by ext4_read_inode_bitmap(), causing a refcnt leak.
Fix this issue by calling brelse() when ext4_iget() fails.
--- fs/ext4/ialloc.c | 1 + 1 file changed, 1 insertion(+)
fs/ext4/ialloc.c +1 -0
@@ -1246,6 +1246,7 @@ struct inode *ext4_orphan_get(struct supext4_error_err (sb, -err,"couldn't read orphan inode %lu (err %d)" , ino, err); +brelse (bitmap_bh);return inode; }
Greg Kroah-Hartman
maintainerPATCH 282/376 ext4: fix error pointer dereference
In reply to Greg Kroah-HartmanFrom: Jeffle Xu <[email protected]>
commit 8418897f1bf87da0cb6936489d57a4320c32c0af upstream.
Don't pass error pointers to brelse().
commit 7159a986b420 ("ext4: fix some error pointer dereferences") has fixed some cases, fix the remaining one case.
Once ext4_xattr_block_find()->ext4_sb_bread() failed, error pointer is stored in @bs->bh, which will be passed to brelse() in the cleanup routine of ext4_xattr_set_handle(). This will then cause a NULL panic crash in __brelse().
BUG: unable to handle kernel NULL pointer dereference at 000000000000005b RIP: 0010:__brelse+0x1b/0x50 Call Trace: ext4_xattr_set_handle+0x163/0x5d0 ext4_xattr_set+0x95/0x110 __vfs_setxattr+0x6b/0x80 __vfs_setxattr_noperm+0x68/0x1b0 vfs_setxattr+0xa0/0xb0 setxattr+0x12c/0x1a0 path_setxattr+0x8d/0xc0 __x64_sys_setxattr+0x27/0x30 do_syscall_64+0x60/0x250 entry_SYSCALL_64_after_hwframe+0x49/0xbe
In this case, @bs->bh stores '-EIO' actually.
--- fs/ext4/xattr.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
fs/ext4/xattr.c +5 -2
@@ -1800,8 +1800,11 @@ ext4_xattr_block_find(struct inode *inodif (EXT4_I (inode)->i_file_acl) {/* The inode already has an extended attribute block. */ bs->bh =ext4_sb_bread (sb,EXT4_I (inode)->i_file_acl,REQ_PRIO ); -if (IS_ERR (bs->bh)) -return PTR_ERR (bs->bh); +if (IS_ERR (bs->bh)) { + error =PTR_ERR (bs->bh); + bs->bh =NULL ; +return error; + }ea_bdebug (bs->bh,"b_count=%d, refcount=%d" ,atomic_read (&(bs->bh->b_count)),le32_to_cpu (BHDR (bs->bh)->h_refcount));