Merge 4.19.292 into android-4.19-stable

Changes in 4.19.292
	sparc: fix up arch_cpu_finalize_init() build breakage.
	mmc: moxart: read scr register without changing byte order
	ipv6: adjust ndisc_is_useropt() to also return true for PIO
	dmaengine: pl330: Return DMA_PAUSED when transaction is paused
	drm/nouveau/gr: enable memory loads on helper invocation on all channels
	radix tree test suite: fix incorrect allocation size for pthreads
	nilfs2: fix use-after-free of nilfs_root in dirtying inodes via iput
	iio: cros_ec: Fix the allocation size for cros_ec_command
	binder: fix memory leak in binder_init()
	usb-storage: alauda: Fix uninit-value in alauda_check_media()
	usb: dwc3: Properly handle processing of pending events
	x86/cpu/amd: Enable Zenbleed fix for AMD Custom APU 0405
	x86/mm: Fix VDSO and VVAR placement on 5-level paging machines
	x86: Move gds_ucode_mitigated() declaration to header
	drm/nouveau/disp: Revert a NULL check inside nouveau_connector_get_modes
	mISDN: Update parameter type of dsp_cmx_send()
	net/packet: annotate data-races around tp->status
	bonding: Fix incorrect deletion of ETH_P_8021AD protocol vid from slaves
	dccp: fix data-race around dp->dccps_mss_cache
	drivers: net: prevent tun_build_skb() to exceed the packet size limit
	IB/hfi1: Fix possible panic during hotplug remove
	wifi: cfg80211: fix sband iftype data lookup for AP_VLAN
	ibmvnic: Handle DMA unmapping of login buffs in release functions
	btrfs: don't stop integrity writeback too early
	netfilter: nf_tables: bogus EBUSY when deleting flowtable after flush
	netfilter: nf_tables: report use refcount overflow
	scsi: core: Fix legacy /proc parsing buffer overflow
	scsi: storvsc: Fix handling of virtual Fibre Channel timeouts
	scsi: 53c700: Check that command slot is not NULL
	scsi: snic: Fix possible memory leak if device_add() fails
	scsi: core: Fix possible memory leak if device_add() fails
	alpha: remove __init annotation from exported page_is_ram()
	sch_netem: fix issues in netem_change() vs get_dist_table()
	Linux 4.19.292

Change-Id: Ie4a1393c672e280631d9a0949e081f134dff3e3b
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
Greg Kroah-Hartman
2023-08-23 15:00:51 +00:00
49 changed files with 348 additions and 168 deletions

View File

@@ -1,7 +1,7 @@
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
VERSION = 4 VERSION = 4
PATCHLEVEL = 19 PATCHLEVEL = 19
SUBLEVEL = 291 SUBLEVEL = 292
EXTRAVERSION = EXTRAVERSION =
NAME = "People's Front" NAME = "People's Front"

View File

@@ -469,8 +469,7 @@ setup_memory(void *kernel_end)
extern void setup_memory(void *); extern void setup_memory(void *);
#endif /* !CONFIG_DISCONTIGMEM */ #endif /* !CONFIG_DISCONTIGMEM */
int __init int page_is_ram(unsigned long pfn)
page_is_ram(unsigned long pfn)
{ {
struct memclust_struct * cluster; struct memclust_struct * cluster;
struct memdesc_struct * memdesc; struct memdesc_struct * memdesc;

View File

@@ -12,7 +12,6 @@ config 64BIT
config SPARC config SPARC
bool bool
default y default y
select ARCH_HAS_CPU_FINALIZE_INIT if !SMP
select ARCH_MIGHT_HAVE_PC_PARPORT if SPARC64 && PCI select ARCH_MIGHT_HAVE_PC_PARPORT if SPARC64 && PCI
select ARCH_MIGHT_HAVE_PC_SERIO select ARCH_MIGHT_HAVE_PC_SERIO
select OF select OF
@@ -51,6 +50,7 @@ config SPARC
config SPARC32 config SPARC32
def_bool !64BIT def_bool !64BIT
select ARCH_HAS_CPU_FINALIZE_INIT if !SMP
select ARCH_HAS_SYNC_DMA_FOR_CPU select ARCH_HAS_SYNC_DMA_FOR_CPU
select DMA_NONCOHERENT_OPS select DMA_NONCOHERENT_OPS
select GENERIC_ATOMIC64 select GENERIC_ATOMIC64

View File

@@ -228,8 +228,8 @@ static unsigned long vdso_addr(unsigned long start, unsigned len)
/* Round the lowest possible end address up to a PMD boundary. */ /* Round the lowest possible end address up to a PMD boundary. */
end = (start + len + PMD_SIZE - 1) & PMD_MASK; end = (start + len + PMD_SIZE - 1) & PMD_MASK;
if (end >= TASK_SIZE_MAX) if (end >= DEFAULT_MAP_WINDOW)
end = TASK_SIZE_MAX; end = DEFAULT_MAP_WINDOW;
end -= len; end -= len;
if (end > start) { if (end > start) {

View File

@@ -991,4 +991,6 @@ enum taa_mitigations {
TAA_MITIGATION_TSX_DISABLED, TAA_MITIGATION_TSX_DISABLED,
}; };
extern bool gds_ucode_mitigated(void);
#endif /* _ASM_X86_PROCESSOR_H */ #endif /* _ASM_X86_PROCESSOR_H */

View File

@@ -69,6 +69,7 @@ static const int amd_erratum_1054[] =
static const int amd_zenbleed[] = static const int amd_zenbleed[] =
AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x30, 0x0, 0x4f, 0xf), AMD_LEGACY_ERRATUM(AMD_MODEL_RANGE(0x17, 0x30, 0x0, 0x4f, 0xf),
AMD_MODEL_RANGE(0x17, 0x60, 0x0, 0x7f, 0xf), AMD_MODEL_RANGE(0x17, 0x60, 0x0, 0x7f, 0xf),
AMD_MODEL_RANGE(0x17, 0x90, 0x0, 0x91, 0xf),
AMD_MODEL_RANGE(0x17, 0xa0, 0x0, 0xaf, 0xf)); AMD_MODEL_RANGE(0x17, 0xa0, 0x0, 0xaf, 0xf));
static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum) static bool cpu_has_amd_erratum(struct cpuinfo_x86 *cpu, const int *erratum)

View File

@@ -217,8 +217,6 @@ struct kvm_stats_debugfs_item debugfs_entries[] = {
u64 __read_mostly host_xcr0; u64 __read_mostly host_xcr0;
extern bool gds_ucode_mitigated(void);
static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt); static int emulator_fix_hypercall(struct x86_emulate_ctxt *ctxt);
static inline void kvm_async_pf_hash_reset(struct kvm_vcpu *vcpu) static inline void kvm_async_pf_hash_reset(struct kvm_vcpu *vcpu)

View File

@@ -6192,6 +6192,7 @@ static int __init binder_init(void)
err_alloc_device_names_failed: err_alloc_device_names_failed:
debugfs_remove_recursive(binder_debugfs_dir_entry_root); debugfs_remove_recursive(binder_debugfs_dir_entry_root);
binder_alloc_shrinker_exit();
return ret; return ret;
} }

View File

@@ -1047,6 +1047,12 @@ static struct shrinker binder_shrinker = {
.seeks = DEFAULT_SEEKS, .seeks = DEFAULT_SEEKS,
}; };
void binder_alloc_shrinker_exit(void)
{
unregister_shrinker(&binder_shrinker);
list_lru_destroy(&binder_alloc_lru);
}
/** /**
* binder_alloc_init() - called by binder_open() for per-proc initialization * binder_alloc_init() - called by binder_open() for per-proc initialization
* @alloc: binder_alloc for this proc * @alloc: binder_alloc for this proc

View File

@@ -132,6 +132,7 @@ extern struct binder_buffer *binder_alloc_new_buf(struct binder_alloc *alloc,
int pid); int pid);
extern void binder_alloc_init(struct binder_alloc *alloc); extern void binder_alloc_init(struct binder_alloc *alloc);
extern int binder_alloc_shrinker_init(void); extern int binder_alloc_shrinker_init(void);
extern void binder_alloc_shrinker_exit(void);
extern void binder_alloc_vma_close(struct binder_alloc *alloc); extern void binder_alloc_vma_close(struct binder_alloc *alloc);
extern struct binder_buffer * extern struct binder_buffer *
binder_alloc_prepare_to_free(struct binder_alloc *alloc, binder_alloc_prepare_to_free(struct binder_alloc *alloc,

View File

@@ -404,6 +404,12 @@ enum desc_status {
* of a channel can be BUSY at any time. * of a channel can be BUSY at any time.
*/ */
BUSY, BUSY,
/*
* Pause was called while descriptor was BUSY. Due to hardware
* limitations, only termination is possible for descriptors
* that have been paused.
*/
PAUSED,
/* /*
* Sitting on the channel work_list but xfer done * Sitting on the channel work_list but xfer done
* by PL330 core * by PL330 core
@@ -2028,7 +2034,7 @@ static inline void fill_queue(struct dma_pl330_chan *pch)
list_for_each_entry(desc, &pch->work_list, node) { list_for_each_entry(desc, &pch->work_list, node) {
/* If already submitted */ /* If already submitted */
if (desc->status == BUSY) if (desc->status == BUSY || desc->status == PAUSED)
continue; continue;
ret = pl330_submit_req(pch->thread, desc); ret = pl330_submit_req(pch->thread, desc);
@@ -2305,6 +2311,7 @@ static int pl330_pause(struct dma_chan *chan)
{ {
struct dma_pl330_chan *pch = to_pchan(chan); struct dma_pl330_chan *pch = to_pchan(chan);
struct pl330_dmac *pl330 = pch->dmac; struct pl330_dmac *pl330 = pch->dmac;
struct dma_pl330_desc *desc;
unsigned long flags; unsigned long flags;
pm_runtime_get_sync(pl330->ddma.dev); pm_runtime_get_sync(pl330->ddma.dev);
@@ -2314,6 +2321,10 @@ static int pl330_pause(struct dma_chan *chan)
_stop(pch->thread); _stop(pch->thread);
spin_unlock(&pl330->lock); spin_unlock(&pl330->lock);
list_for_each_entry(desc, &pch->work_list, node) {
if (desc->status == BUSY)
desc->status = PAUSED;
}
spin_unlock_irqrestore(&pch->lock, flags); spin_unlock_irqrestore(&pch->lock, flags);
pm_runtime_mark_last_busy(pl330->ddma.dev); pm_runtime_mark_last_busy(pl330->ddma.dev);
pm_runtime_put_autosuspend(pl330->ddma.dev); pm_runtime_put_autosuspend(pl330->ddma.dev);
@@ -2404,7 +2415,7 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
else if (running && desc == running) else if (running && desc == running)
transferred = transferred =
pl330_get_current_xferred_count(pch, desc); pl330_get_current_xferred_count(pch, desc);
else if (desc->status == BUSY) else if (desc->status == BUSY || desc->status == PAUSED)
/* /*
* Busy but not running means either just enqueued, * Busy but not running means either just enqueued,
* or finished and not yet marked done * or finished and not yet marked done
@@ -2421,6 +2432,9 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
case DONE: case DONE:
ret = DMA_COMPLETE; ret = DMA_COMPLETE;
break; break;
case PAUSED:
ret = DMA_PAUSED;
break;
case PREP: case PREP:
case BUSY: case BUSY:
ret = DMA_IN_PROGRESS; ret = DMA_IN_PROGRESS;

View File

@@ -921,7 +921,7 @@ nouveau_connector_get_modes(struct drm_connector *connector)
/* Determine display colour depth for everything except LVDS now, /* Determine display colour depth for everything except LVDS now,
* DP requires this before mode_valid() is called. * DP requires this before mode_valid() is called.
*/ */
if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS && nv_connector->native_mode) if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS)
nouveau_connector_detect_depth(connector); nouveau_connector_detect_depth(connector);
/* Find the native mode if this is a digital panel, if we didn't /* Find the native mode if this is a digital panel, if we didn't

View File

@@ -121,6 +121,7 @@ void gk104_grctx_generate_r418800(struct gf100_gr *);
extern const struct gf100_grctx_func gk110_grctx; extern const struct gf100_grctx_func gk110_grctx;
void gk110_grctx_generate_r419eb0(struct gf100_gr *); void gk110_grctx_generate_r419eb0(struct gf100_gr *);
void gk110_grctx_generate_r419f78(struct gf100_gr *);
extern const struct gf100_grctx_func gk110b_grctx; extern const struct gf100_grctx_func gk110b_grctx;
extern const struct gf100_grctx_func gk208_grctx; extern const struct gf100_grctx_func gk208_grctx;

View File

@@ -916,7 +916,9 @@ static void
gk104_grctx_generate_r419f78(struct gf100_gr *gr) gk104_grctx_generate_r419f78(struct gf100_gr *gr)
{ {
struct nvkm_device *device = gr->base.engine.subdev.device; struct nvkm_device *device = gr->base.engine.subdev.device;
nvkm_mask(device, 0x419f78, 0x00000001, 0x00000000);
/* bit 3 set disables loads in fp helper invocations, we need it enabled */
nvkm_mask(device, 0x419f78, 0x00000009, 0x00000000);
} }
void void

View File

@@ -820,6 +820,15 @@ gk110_grctx_generate_r419eb0(struct gf100_gr *gr)
nvkm_mask(device, 0x419eb0, 0x00001000, 0x00001000); nvkm_mask(device, 0x419eb0, 0x00001000, 0x00001000);
} }
void
gk110_grctx_generate_r419f78(struct gf100_gr *gr)
{
struct nvkm_device *device = gr->base.engine.subdev.device;
/* bit 3 set disables loads in fp helper invocations, we need it enabled */
nvkm_mask(device, 0x419f78, 0x00000008, 0x00000000);
}
const struct gf100_grctx_func const struct gf100_grctx_func
gk110_grctx = { gk110_grctx = {
.main = gf100_grctx_generate_main, .main = gf100_grctx_generate_main,
@@ -852,4 +861,5 @@ gk110_grctx = {
.gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr, .gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr,
.r418800 = gk104_grctx_generate_r418800, .r418800 = gk104_grctx_generate_r418800,
.r419eb0 = gk110_grctx_generate_r419eb0, .r419eb0 = gk110_grctx_generate_r419eb0,
.r419f78 = gk110_grctx_generate_r419f78,
}; };

View File

@@ -101,4 +101,5 @@ gk110b_grctx = {
.gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr, .gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr,
.r418800 = gk104_grctx_generate_r418800, .r418800 = gk104_grctx_generate_r418800,
.r419eb0 = gk110_grctx_generate_r419eb0, .r419eb0 = gk110_grctx_generate_r419eb0,
.r419f78 = gk110_grctx_generate_r419f78,
}; };

View File

@@ -566,4 +566,5 @@ gk208_grctx = {
.dist_skip_table = gf117_grctx_generate_dist_skip_table, .dist_skip_table = gf117_grctx_generate_dist_skip_table,
.gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr, .gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr,
.r418800 = gk104_grctx_generate_r418800, .r418800 = gk104_grctx_generate_r418800,
.r419f78 = gk110_grctx_generate_r419f78,
}; };

View File

@@ -991,4 +991,5 @@ gm107_grctx = {
.r406500 = gm107_grctx_generate_r406500, .r406500 = gm107_grctx_generate_r406500,
.gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr, .gpc_tpc_nr = gk104_grctx_generate_gpc_tpc_nr,
.r419e00 = gm107_grctx_generate_r419e00, .r419e00 = gm107_grctx_generate_r419e00,
.r419f78 = gk110_grctx_generate_r419f78,
}; };

View File

@@ -46,7 +46,7 @@ int cros_ec_sensors_core_init(struct platform_device *pdev,
platform_set_drvdata(pdev, indio_dev); platform_set_drvdata(pdev, indio_dev);
state->ec = ec->ec_dev; state->ec = ec->ec_dev;
state->msg = devm_kzalloc(&pdev->dev, state->msg = devm_kzalloc(&pdev->dev, sizeof(*state->msg) +
max((u16)sizeof(struct ec_params_motion_sense), max((u16)sizeof(struct ec_params_motion_sense),
state->ec->max_response), GFP_KERNEL); state->ec->max_response), GFP_KERNEL);
if (!state->msg) if (!state->msg)

View File

@@ -12178,6 +12178,7 @@ static void free_cntrs(struct hfi1_devdata *dd)
if (dd->synth_stats_timer.function) if (dd->synth_stats_timer.function)
del_timer_sync(&dd->synth_stats_timer); del_timer_sync(&dd->synth_stats_timer);
cancel_work_sync(&dd->update_cntr_work);
ppd = (struct hfi1_pportdata *)(dd + 1); ppd = (struct hfi1_pportdata *)(dd + 1);
for (i = 0; i < dd->num_pports; i++, ppd++) { for (i = 0; i < dd->num_pports; i++, ppd++) {
kfree(ppd->cntrs); kfree(ppd->cntrs);

View File

@@ -247,7 +247,7 @@ extern void dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp);
extern int dsp_cmx_conf(struct dsp *dsp, u32 conf_id); extern int dsp_cmx_conf(struct dsp *dsp, u32 conf_id);
extern void dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb); extern void dsp_cmx_receive(struct dsp *dsp, struct sk_buff *skb);
extern void dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb); extern void dsp_cmx_hdlc(struct dsp *dsp, struct sk_buff *skb);
extern void dsp_cmx_send(void *arg); extern void dsp_cmx_send(struct timer_list *arg);
extern void dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb); extern void dsp_cmx_transmit(struct dsp *dsp, struct sk_buff *skb);
extern int dsp_cmx_del_conf_member(struct dsp *dsp); extern int dsp_cmx_del_conf_member(struct dsp *dsp);
extern int dsp_cmx_del_conf(struct dsp_conf *conf); extern int dsp_cmx_del_conf(struct dsp_conf *conf);

View File

@@ -1625,7 +1625,7 @@ static u16 dsp_count; /* last sample count */
static int dsp_count_valid; /* if we have last sample count */ static int dsp_count_valid; /* if we have last sample count */
void void
dsp_cmx_send(void *arg) dsp_cmx_send(struct timer_list *arg)
{ {
struct dsp_conf *conf; struct dsp_conf *conf;
struct dsp_conf_member *member; struct dsp_conf_member *member;

View File

@@ -1202,7 +1202,7 @@ static int __init dsp_init(void)
} }
/* set sample timer */ /* set sample timer */
timer_setup(&dsp_spl_tl, (void *)dsp_cmx_send, 0); timer_setup(&dsp_spl_tl, dsp_cmx_send, 0);
dsp_spl_tl.expires = jiffies + dsp_tics; dsp_spl_tl.expires = jiffies + dsp_tics;
dsp_spl_jiffies = dsp_spl_tl.expires; dsp_spl_jiffies = dsp_spl_tl.expires;
add_timer(&dsp_spl_tl); add_timer(&dsp_spl_tl);

View File

@@ -339,13 +339,7 @@ static void moxart_transfer_pio(struct moxart_host *host)
return; return;
} }
for (len = 0; len < remain && len < host->fifo_width;) { for (len = 0; len < remain && len < host->fifo_width;) {
/* SCR data must be read in big endian. */ *sgp = ioread32(host->base + REG_DATA_WINDOW);
if (data->mrq->cmd->opcode == SD_APP_SEND_SCR)
*sgp = ioread32be(host->base +
REG_DATA_WINDOW);
else
*sgp = ioread32(host->base +
REG_DATA_WINDOW);
sgp++; sgp++;
len += 4; len += 4;
} }

View File

@@ -4395,7 +4395,9 @@ void bond_setup(struct net_device *bond_dev)
bond_dev->hw_features = BOND_VLAN_FEATURES | bond_dev->hw_features = BOND_VLAN_FEATURES |
NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_FILTER; NETIF_F_HW_VLAN_CTAG_FILTER |
NETIF_F_HW_VLAN_STAG_RX |
NETIF_F_HW_VLAN_STAG_FILTER;
bond_dev->hw_features |= NETIF_F_GSO_ENCAP_ALL | NETIF_F_GSO_UDP_L4; bond_dev->hw_features |= NETIF_F_GSO_ENCAP_ALL | NETIF_F_GSO_UDP_L4;
bond_dev->features |= bond_dev->hw_features; bond_dev->features |= bond_dev->hw_features;

View File

@@ -884,12 +884,22 @@ static int ibmvnic_login(struct net_device *netdev)
static void release_login_buffer(struct ibmvnic_adapter *adapter) static void release_login_buffer(struct ibmvnic_adapter *adapter)
{ {
if (!adapter->login_buf)
return;
dma_unmap_single(&adapter->vdev->dev, adapter->login_buf_token,
adapter->login_buf_sz, DMA_TO_DEVICE);
kfree(adapter->login_buf); kfree(adapter->login_buf);
adapter->login_buf = NULL; adapter->login_buf = NULL;
} }
static void release_login_rsp_buffer(struct ibmvnic_adapter *adapter) static void release_login_rsp_buffer(struct ibmvnic_adapter *adapter)
{ {
if (!adapter->login_rsp_buf)
return;
dma_unmap_single(&adapter->vdev->dev, adapter->login_rsp_buf_token,
adapter->login_rsp_buf_sz, DMA_FROM_DEVICE);
kfree(adapter->login_rsp_buf); kfree(adapter->login_rsp_buf);
adapter->login_rsp_buf = NULL; adapter->login_rsp_buf = NULL;
} }
@@ -4061,11 +4071,6 @@ static int handle_login_rsp(union ibmvnic_crq *login_rsp_crq,
struct ibmvnic_login_buffer *login = adapter->login_buf; struct ibmvnic_login_buffer *login = adapter->login_buf;
int i; int i;
dma_unmap_single(dev, adapter->login_buf_token, adapter->login_buf_sz,
DMA_TO_DEVICE);
dma_unmap_single(dev, adapter->login_rsp_buf_token,
adapter->login_rsp_buf_sz, DMA_FROM_DEVICE);
/* If the number of queues requested can't be allocated by the /* If the number of queues requested can't be allocated by the
* server, the login response will return with code 1. We will need * server, the login response will return with code 1. We will need
* to resend the login buffer with fewer queues requested. * to resend the login buffer with fewer queues requested.

View File

@@ -1654,7 +1654,7 @@ static bool tun_can_build_skb(struct tun_struct *tun, struct tun_file *tfile,
if (zerocopy) if (zerocopy)
return false; return false;
if (SKB_DATA_ALIGN(len + TUN_RX_PAD) + if (SKB_DATA_ALIGN(len + TUN_RX_PAD + XDP_PACKET_HEADROOM) +
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) > PAGE_SIZE) SKB_DATA_ALIGN(sizeof(struct skb_shared_info)) > PAGE_SIZE)
return false; return false;

View File

@@ -1594,7 +1594,7 @@ NCR_700_intr(int irq, void *dev_id)
printk("scsi%d (%d:%d) PHASE MISMATCH IN SEND MESSAGE %d remain, return %p[%04x], phase %s\n", host->host_no, pun, lun, count, (void *)temp, temp - hostdata->pScript, sbcl_to_string(NCR_700_readb(host, SBCL_REG))); printk("scsi%d (%d:%d) PHASE MISMATCH IN SEND MESSAGE %d remain, return %p[%04x], phase %s\n", host->host_no, pun, lun, count, (void *)temp, temp - hostdata->pScript, sbcl_to_string(NCR_700_readb(host, SBCL_REG)));
#endif #endif
resume_offset = hostdata->pScript + Ent_SendMessagePhaseMismatch; resume_offset = hostdata->pScript + Ent_SendMessagePhaseMismatch;
} else if(dsp >= to32bit(&slot->pSG[0].ins) && } else if (slot && dsp >= to32bit(&slot->pSG[0].ins) &&
dsp <= to32bit(&slot->pSG[NCR_700_SG_SEGMENTS].ins)) { dsp <= to32bit(&slot->pSG[NCR_700_SG_SEGMENTS].ins)) {
int data_transfer = NCR_700_readl(host, DBC_REG) & 0xffffff; int data_transfer = NCR_700_readl(host, DBC_REG) & 0xffffff;
int SGcount = (dsp - to32bit(&slot->pSG[0].ins))/sizeof(struct NCR_700_SG_List); int SGcount = (dsp - to32bit(&slot->pSG[0].ins))/sizeof(struct NCR_700_SG_List);

View File

@@ -249,6 +249,7 @@ int raid_component_add(struct raid_template *r,struct device *raid_dev,
return 0; return 0;
err_out: err_out:
put_device(&rc->dev);
list_del(&rc->node); list_del(&rc->node);
rd->component_count--; rd->component_count--;
put_device(component_dev); put_device(component_dev);

View File

@@ -311,7 +311,7 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
size_t length, loff_t *ppos) size_t length, loff_t *ppos)
{ {
int host, channel, id, lun; int host, channel, id, lun;
char *buffer, *p; char *buffer, *end, *p;
int err; int err;
if (!buf || length > PAGE_SIZE) if (!buf || length > PAGE_SIZE)
@@ -326,10 +326,14 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
goto out; goto out;
err = -EINVAL; err = -EINVAL;
if (length < PAGE_SIZE) if (length < PAGE_SIZE) {
buffer[length] = '\0'; end = buffer + length;
else if (buffer[PAGE_SIZE-1]) *end = '\0';
goto out; } else {
end = buffer + PAGE_SIZE - 1;
if (*end)
goto out;
}
/* /*
* Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
@@ -338,10 +342,10 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
if (!strncmp("scsi add-single-device", buffer, 22)) { if (!strncmp("scsi add-single-device", buffer, 22)) {
p = buffer + 23; p = buffer + 23;
host = simple_strtoul(p, &p, 0); host = (p < end) ? simple_strtoul(p, &p, 0) : 0;
channel = simple_strtoul(p + 1, &p, 0); channel = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0;
id = simple_strtoul(p + 1, &p, 0); id = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0;
lun = simple_strtoul(p + 1, &p, 0); lun = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0;
err = scsi_add_single_device(host, channel, id, lun); err = scsi_add_single_device(host, channel, id, lun);
@@ -352,10 +356,10 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
} else if (!strncmp("scsi remove-single-device", buffer, 25)) { } else if (!strncmp("scsi remove-single-device", buffer, 25)) {
p = buffer + 26; p = buffer + 26;
host = simple_strtoul(p, &p, 0); host = (p < end) ? simple_strtoul(p, &p, 0) : 0;
channel = simple_strtoul(p + 1, &p, 0); channel = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0;
id = simple_strtoul(p + 1, &p, 0); id = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0;
lun = simple_strtoul(p + 1, &p, 0); lun = (p + 1 < end) ? simple_strtoul(p + 1, &p, 0) : 0;
err = scsi_remove_single_device(host, channel, id, lun); err = scsi_remove_single_device(host, channel, id, lun);
} }

View File

@@ -316,6 +316,7 @@ snic_tgt_create(struct snic *snic, struct snic_tgt_id *tgtid)
"Snic Tgt: device_add, with err = %d\n", "Snic Tgt: device_add, with err = %d\n",
ret); ret);
put_device(&tgt->dev);
put_device(&snic->shost->shost_gendev); put_device(&snic->shost->shost_gendev);
spin_lock_irqsave(snic->shost->host_lock, flags); spin_lock_irqsave(snic->shost->host_lock, flags);
list_del(&tgt->list); list_del(&tgt->list);

View File

@@ -1540,10 +1540,6 @@ static int storvsc_host_reset_handler(struct scsi_cmnd *scmnd)
*/ */
static enum blk_eh_timer_return storvsc_eh_timed_out(struct scsi_cmnd *scmnd) static enum blk_eh_timer_return storvsc_eh_timed_out(struct scsi_cmnd *scmnd)
{ {
#if IS_ENABLED(CONFIG_SCSI_FC_ATTRS)
if (scmnd->device->host->transportt == fc_transport_template)
return fc_eh_timed_out(scmnd);
#endif
return BLK_EH_RESET_TIMER; return BLK_EH_RESET_TIMER;
} }

View File

@@ -3234,9 +3234,14 @@ static irqreturn_t dwc3_check_event_buf(struct dwc3_event_buffer *evt)
u32 reg; u32 reg;
if (pm_runtime_suspended(dwc->dev)) { if (pm_runtime_suspended(dwc->dev)) {
dwc->pending_events = true;
/*
* Trigger runtime resume. The get() function will be balanced
* after processing the pending events in dwc3_process_pending
* events().
*/
pm_runtime_get(dwc->dev); pm_runtime_get(dwc->dev);
disable_irq_nosync(dwc->irq_gadget); disable_irq_nosync(dwc->irq_gadget);
dwc->pending_events = true;
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@@ -3474,6 +3479,8 @@ void dwc3_gadget_process_pending_events(struct dwc3 *dwc)
{ {
if (dwc->pending_events) { if (dwc->pending_events) {
dwc3_interrupt(dwc->irq_gadget, dwc->ev_buf); dwc3_interrupt(dwc->irq_gadget, dwc->ev_buf);
dwc3_thread_interrupt(dwc->irq_gadget, dwc->ev_buf);
pm_runtime_put(dwc->dev);
dwc->pending_events = false; dwc->pending_events = false;
enable_irq(dwc->irq_gadget); enable_irq(dwc->irq_gadget);
} }

View File

@@ -317,7 +317,8 @@ static int alauda_get_media_status(struct us_data *us, unsigned char *data)
rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe, rc = usb_stor_ctrl_transfer(us, us->recv_ctrl_pipe,
command, 0xc0, 0, 1, data, 2); command, 0xc0, 0, 1, data, 2);
usb_stor_dbg(us, "Media status %02X %02X\n", data[0], data[1]); if (rc == USB_STOR_XFER_GOOD)
usb_stor_dbg(us, "Media status %02X %02X\n", data[0], data[1]);
return rc; return rc;
} }
@@ -453,10 +454,14 @@ static int alauda_init_media(struct us_data *us)
static int alauda_check_media(struct us_data *us) static int alauda_check_media(struct us_data *us)
{ {
struct alauda_info *info = (struct alauda_info *) us->extra; struct alauda_info *info = (struct alauda_info *) us->extra;
unsigned char status[2]; unsigned char *status = us->iobuf;
int rc; int rc;
rc = alauda_get_media_status(us, status); rc = alauda_get_media_status(us, status);
if (rc != USB_STOR_XFER_GOOD) {
status[0] = 0xF0; /* Pretend there's no media */
status[1] = 0;
}
/* Check for no media or door open */ /* Check for no media or door open */
if ((status[0] & 0x80) || ((status[0] & 0x1F) == 0x10) if ((status[0] & 0x80) || ((status[0] & 0x1F) == 0x10)

View File

@@ -3928,11 +3928,12 @@ int btree_write_cache_pages(struct address_space *mapping,
free_extent_buffer(eb); free_extent_buffer(eb);
/* /*
* the filesystem may choose to bump up nr_to_write. * The filesystem may choose to bump up nr_to_write.
* We have to make sure to honor the new nr_to_write * We have to make sure to honor the new nr_to_write
* at any time * at any time.
*/ */
nr_to_write_done = wbc->nr_to_write <= 0; nr_to_write_done = (wbc->sync_mode == WB_SYNC_NONE &&
wbc->nr_to_write <= 0);
} }
pagevec_release(&pvec); pagevec_release(&pvec);
cond_resched(); cond_resched();

View File

@@ -1112,9 +1112,17 @@ int nilfs_set_file_dirty(struct inode *inode, unsigned int nr_dirty)
int __nilfs_mark_inode_dirty(struct inode *inode, int flags) int __nilfs_mark_inode_dirty(struct inode *inode, int flags)
{ {
struct the_nilfs *nilfs = inode->i_sb->s_fs_info;
struct buffer_head *ibh; struct buffer_head *ibh;
int err; int err;
/*
* Do not dirty inodes after the log writer has been detached
* and its nilfs_root struct has been freed.
*/
if (unlikely(nilfs_purging(nilfs)))
return 0;
err = nilfs_load_inode_block(inode, &ibh); err = nilfs_load_inode_block(inode, &ibh);
if (unlikely(err)) { if (unlikely(err)) {
nilfs_msg(inode->i_sb, KERN_WARNING, nilfs_msg(inode->i_sb, KERN_WARNING,

View File

@@ -2845,6 +2845,7 @@ void nilfs_detach_log_writer(struct super_block *sb)
nilfs_segctor_destroy(nilfs->ns_writer); nilfs_segctor_destroy(nilfs->ns_writer);
nilfs->ns_writer = NULL; nilfs->ns_writer = NULL;
} }
set_nilfs_purging(nilfs);
/* Force to free the list of dirty files */ /* Force to free the list of dirty files */
spin_lock(&nilfs->ns_inode_lock); spin_lock(&nilfs->ns_inode_lock);
@@ -2857,4 +2858,5 @@ void nilfs_detach_log_writer(struct super_block *sb)
up_write(&nilfs->ns_segctor_sem); up_write(&nilfs->ns_segctor_sem);
nilfs_dispose_list(nilfs, &garbage_list, 1); nilfs_dispose_list(nilfs, &garbage_list, 1);
clear_nilfs_purging(nilfs);
} }

View File

@@ -29,6 +29,7 @@ enum {
THE_NILFS_DISCONTINUED, /* 'next' pointer chain has broken */ THE_NILFS_DISCONTINUED, /* 'next' pointer chain has broken */
THE_NILFS_GC_RUNNING, /* gc process is running */ THE_NILFS_GC_RUNNING, /* gc process is running */
THE_NILFS_SB_DIRTY, /* super block is dirty */ THE_NILFS_SB_DIRTY, /* super block is dirty */
THE_NILFS_PURGING, /* disposing dirty files for cleanup */
}; };
/** /**
@@ -208,6 +209,7 @@ THE_NILFS_FNS(INIT, init)
THE_NILFS_FNS(DISCONTINUED, discontinued) THE_NILFS_FNS(DISCONTINUED, discontinued)
THE_NILFS_FNS(GC_RUNNING, gc_running) THE_NILFS_FNS(GC_RUNNING, gc_running)
THE_NILFS_FNS(SB_DIRTY, sb_dirty) THE_NILFS_FNS(SB_DIRTY, sb_dirty)
THE_NILFS_FNS(PURGING, purging)
/* /*
* Mount option operations * Mount option operations

View File

@@ -429,6 +429,9 @@ ieee80211_get_sband_iftype_data(const struct ieee80211_supported_band *sband,
if (WARN_ON(iftype >= NL80211_IFTYPE_MAX)) if (WARN_ON(iftype >= NL80211_IFTYPE_MAX))
return NULL; return NULL;
if (iftype == NL80211_IFTYPE_AP_VLAN)
iftype = NL80211_IFTYPE_AP;
for (i = 0; i < sband->n_iftype_data; i++) { for (i = 0; i < sband->n_iftype_data; i++) {
const struct ieee80211_sband_iftype_data *data = const struct ieee80211_sband_iftype_data *data =
&sband->iftype_data[i]; &sband->iftype_data[i];

View File

@@ -992,6 +992,29 @@ int __nft_release_basechain(struct nft_ctx *ctx);
unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv); unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv);
static inline bool nft_use_inc(u32 *use)
{
if (*use == UINT_MAX)
return false;
(*use)++;
return true;
}
static inline void nft_use_dec(u32 *use)
{
WARN_ON_ONCE((*use)-- == 0);
}
/* For error and abort path: restore use counter to previous state. */
static inline void nft_use_inc_restore(u32 *use)
{
WARN_ON_ONCE(!nft_use_inc(use));
}
#define nft_use_dec_restore nft_use_dec
/** /**
* struct nft_table - nf_tables table * struct nft_table - nf_tables table
* *
@@ -1050,8 +1073,8 @@ struct nft_object {
struct list_head list; struct list_head list;
char *name; char *name;
struct nft_table *table; struct nft_table *table;
u32 genmask:2, u32 genmask:2;
use:30; u32 use;
u64 handle; u64 handle;
/* runtime data below here */ /* runtime data below here */
const struct nft_object_ops *ops ____cacheline_aligned; const struct nft_object_ops *ops ____cacheline_aligned;
@@ -1149,8 +1172,8 @@ struct nft_flowtable {
int hooknum; int hooknum;
int priority; int priority;
int ops_len; int ops_len;
u32 genmask:2, u32 genmask:2;
use:30; u32 use;
u64 handle; u64 handle;
/* runtime data below here */ /* runtime data below here */
struct nf_hook_ops *ops ____cacheline_aligned; struct nf_hook_ops *ops ____cacheline_aligned;
@@ -1161,6 +1184,10 @@ struct nft_flowtable *nft_flowtable_lookup(const struct nft_table *table,
const struct nlattr *nla, const struct nlattr *nla,
u8 genmask); u8 genmask);
void nf_tables_deactivate_flowtable(const struct nft_ctx *ctx,
struct nft_flowtable *flowtable,
enum nft_trans_phase phase);
void nft_register_flowtable_type(struct nf_flowtable_type *type); void nft_register_flowtable_type(struct nf_flowtable_type *type);
void nft_unregister_flowtable_type(struct nf_flowtable_type *type); void nft_unregister_flowtable_type(struct nf_flowtable_type *type);

View File

@@ -189,7 +189,7 @@ unsigned int dccp_sync_mss(struct sock *sk, u32 pmtu)
/* And store cached results */ /* And store cached results */
icsk->icsk_pmtu_cookie = pmtu; icsk->icsk_pmtu_cookie = pmtu;
dp->dccps_mss_cache = cur_mps; WRITE_ONCE(dp->dccps_mss_cache, cur_mps);
return cur_mps; return cur_mps;
} }

View File

@@ -648,7 +648,7 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
return dccp_getsockopt_service(sk, len, return dccp_getsockopt_service(sk, len,
(__be32 __user *)optval, optlen); (__be32 __user *)optval, optlen);
case DCCP_SOCKOPT_GET_CUR_MPS: case DCCP_SOCKOPT_GET_CUR_MPS:
val = dp->dccps_mss_cache; val = READ_ONCE(dp->dccps_mss_cache);
break; break;
case DCCP_SOCKOPT_AVAILABLE_CCIDS: case DCCP_SOCKOPT_AVAILABLE_CCIDS:
return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen); return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen);
@@ -770,7 +770,7 @@ int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
trace_dccp_probe(sk, len); trace_dccp_probe(sk, len);
if (len > dp->dccps_mss_cache) if (len > READ_ONCE(dp->dccps_mss_cache))
return -EMSGSIZE; return -EMSGSIZE;
lock_sock(sk); lock_sock(sk);
@@ -803,6 +803,12 @@ int dccp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len)
goto out_discard; goto out_discard;
} }
/* We need to check dccps_mss_cache after socket is locked. */
if (len > dp->dccps_mss_cache) {
rc = -EMSGSIZE;
goto out_discard;
}
skb_reserve(skb, sk->sk_prot->max_header); skb_reserve(skb, sk->sk_prot->max_header);
rc = memcpy_from_msg(skb_put(skb, len), msg, len); rc = memcpy_from_msg(skb_put(skb, len), msg, len);
if (rc != 0) if (rc != 0)

View File

@@ -195,7 +195,8 @@ static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur,
static inline int ndisc_is_useropt(const struct net_device *dev, static inline int ndisc_is_useropt(const struct net_device *dev,
struct nd_opt_hdr *opt) struct nd_opt_hdr *opt)
{ {
return opt->nd_opt_type == ND_OPT_RDNSS || return opt->nd_opt_type == ND_OPT_PREFIX_INFO ||
opt->nd_opt_type == ND_OPT_RDNSS ||
opt->nd_opt_type == ND_OPT_DNSSL || opt->nd_opt_type == ND_OPT_DNSSL ||
opt->nd_opt_type == ND_OPT_CAPTIVE_PORTAL || opt->nd_opt_type == ND_OPT_CAPTIVE_PORTAL ||
opt->nd_opt_type == ND_OPT_PREF64 || opt->nd_opt_type == ND_OPT_PREF64 ||

View File

@@ -266,7 +266,7 @@ static int nft_delchain(struct nft_ctx *ctx)
if (err < 0) if (err < 0)
return err; return err;
ctx->table->use--; nft_use_dec(&ctx->table->use);
nft_deactivate_next(ctx->net, ctx->chain); nft_deactivate_next(ctx->net, ctx->chain);
return err; return err;
@@ -307,7 +307,7 @@ nf_tables_delrule_deactivate(struct nft_ctx *ctx, struct nft_rule *rule)
/* You cannot delete the same rule twice */ /* You cannot delete the same rule twice */
if (nft_is_active_next(ctx->net, rule)) { if (nft_is_active_next(ctx->net, rule)) {
nft_deactivate_next(ctx->net, rule); nft_deactivate_next(ctx->net, rule);
ctx->chain->use--; nft_use_dec(&ctx->chain->use);
return 0; return 0;
} }
return -ENOENT; return -ENOENT;
@@ -396,7 +396,7 @@ static int nft_delset(const struct nft_ctx *ctx, struct nft_set *set)
return err; return err;
nft_deactivate_next(ctx->net, set); nft_deactivate_next(ctx->net, set);
ctx->table->use--; nft_use_dec(&ctx->table->use);
return err; return err;
} }
@@ -428,7 +428,7 @@ static int nft_delobj(struct nft_ctx *ctx, struct nft_object *obj)
return err; return err;
nft_deactivate_next(ctx->net, obj); nft_deactivate_next(ctx->net, obj);
ctx->table->use--; nft_use_dec(&ctx->table->use);
return err; return err;
} }
@@ -462,7 +462,7 @@ static int nft_delflowtable(struct nft_ctx *ctx,
return err; return err;
nft_deactivate_next(ctx->net, flowtable); nft_deactivate_next(ctx->net, flowtable);
ctx->table->use--; nft_use_dec(&ctx->table->use);
return err; return err;
} }
@@ -1660,9 +1660,6 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
struct nft_rule **rules; struct nft_rule **rules;
int err; int err;
if (table->use == UINT_MAX)
return -EOVERFLOW;
if (nla[NFTA_CHAIN_HOOK]) { if (nla[NFTA_CHAIN_HOOK]) {
struct nft_chain_hook hook; struct nft_chain_hook hook;
struct nf_hook_ops *ops; struct nf_hook_ops *ops;
@@ -1734,6 +1731,11 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
if (err < 0) if (err < 0)
goto err1; goto err1;
if (!nft_use_inc(&table->use)) {
err = -EMFILE;
goto err_use;
}
err = rhltable_insert_key(&table->chains_ht, chain->name, err = rhltable_insert_key(&table->chains_ht, chain->name,
&chain->rhlhead, nft_chain_ht_params); &chain->rhlhead, nft_chain_ht_params);
if (err) if (err)
@@ -1746,11 +1748,12 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 genmask,
goto err2; goto err2;
} }
table->use++;
list_add_tail_rcu(&chain->list, &table->chains); list_add_tail_rcu(&chain->list, &table->chains);
return 0; return 0;
err2: err2:
nft_use_dec_restore(&table->use);
err_use:
nf_tables_unregister_hook(net, table, chain); nf_tables_unregister_hook(net, table, chain);
err1: err1:
nf_tables_chain_destroy(ctx); nf_tables_chain_destroy(ctx);
@@ -2692,9 +2695,6 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
return -EINVAL; return -EINVAL;
handle = nf_tables_alloc_handle(table); handle = nf_tables_alloc_handle(table);
if (chain->use == UINT_MAX)
return -EOVERFLOW;
if (nla[NFTA_RULE_POSITION]) { if (nla[NFTA_RULE_POSITION]) {
pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION])); pos_handle = be64_to_cpu(nla_get_be64(nla[NFTA_RULE_POSITION]));
old_rule = __nft_rule_lookup(chain, pos_handle); old_rule = __nft_rule_lookup(chain, pos_handle);
@@ -2770,23 +2770,28 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
expr = nft_expr_next(expr); expr = nft_expr_next(expr);
} }
if (!nft_use_inc(&chain->use)) {
err = -EMFILE;
goto err2;
}
if (nlh->nlmsg_flags & NLM_F_REPLACE) { if (nlh->nlmsg_flags & NLM_F_REPLACE) {
trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule); trans = nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule);
if (trans == NULL) { if (trans == NULL) {
err = -ENOMEM; err = -ENOMEM;
goto err2; goto err_destroy_flow_rule;
} }
err = nft_delrule(&ctx, old_rule); err = nft_delrule(&ctx, old_rule);
if (err < 0) { if (err < 0) {
nft_trans_destroy(trans); nft_trans_destroy(trans);
goto err2; goto err_destroy_flow_rule;
} }
list_add_tail_rcu(&rule->list, &old_rule->list); list_add_tail_rcu(&rule->list, &old_rule->list);
} else { } else {
if (nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule) == NULL) { if (nft_trans_rule_add(&ctx, NFT_MSG_NEWRULE, rule) == NULL) {
err = -ENOMEM; err = -ENOMEM;
goto err2; goto err_destroy_flow_rule;
} }
if (nlh->nlmsg_flags & NLM_F_APPEND) { if (nlh->nlmsg_flags & NLM_F_APPEND) {
@@ -2802,12 +2807,14 @@ static int nf_tables_newrule(struct net *net, struct sock *nlsk,
} }
} }
kvfree(info); kvfree(info);
chain->use++;
if (nft_net->validate_state == NFT_VALIDATE_DO) if (nft_net->validate_state == NFT_VALIDATE_DO)
return nft_table_validate(net, table); return nft_table_validate(net, table);
return 0; return 0;
err_destroy_flow_rule:
nft_use_dec_restore(&chain->use);
err2: err2:
nft_rule_expr_deactivate(&ctx, rule, NFT_TRANS_PREPARE_ERROR); nft_rule_expr_deactivate(&ctx, rule, NFT_TRANS_PREPARE_ERROR);
nf_tables_rule_destroy(&ctx, rule); nf_tables_rule_destroy(&ctx, rule);
@@ -3625,10 +3632,15 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
if (ops->privsize != NULL) if (ops->privsize != NULL)
size = ops->privsize(nla, &desc); size = ops->privsize(nla, &desc);
if (!nft_use_inc(&table->use)) {
err = -EMFILE;
goto err1;
}
set = kvzalloc(sizeof(*set) + size + udlen, GFP_KERNEL); set = kvzalloc(sizeof(*set) + size + udlen, GFP_KERNEL);
if (!set) { if (!set) {
err = -ENOMEM; err = -ENOMEM;
goto err1; goto err_alloc;
} }
name = nla_strdup(nla[NFTA_SET_NAME], GFP_KERNEL); name = nla_strdup(nla[NFTA_SET_NAME], GFP_KERNEL);
@@ -3675,7 +3687,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
goto err4; goto err4;
list_add_tail_rcu(&set->list, &table->sets); list_add_tail_rcu(&set->list, &table->sets);
table->use++;
return 0; return 0;
err4: err4:
@@ -3684,6 +3696,8 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
kfree(set->name); kfree(set->name);
err2: err2:
kvfree(set); kvfree(set);
err_alloc:
nft_use_dec_restore(&table->use);
err1: err1:
module_put(to_set_type(ops)->owner); module_put(to_set_type(ops)->owner);
return err; return err;
@@ -3770,9 +3784,6 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_binding *i; struct nft_set_binding *i;
struct nft_set_iter iter; struct nft_set_iter iter;
if (set->use == UINT_MAX)
return -EOVERFLOW;
if (!list_empty(&set->bindings) && nft_set_is_anonymous(set)) if (!list_empty(&set->bindings) && nft_set_is_anonymous(set))
return -EBUSY; return -EBUSY;
@@ -3797,10 +3808,12 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
return iter.err; return iter.err;
} }
bind: bind:
if (!nft_use_inc(&set->use))
return -EMFILE;
binding->chain = ctx->chain; binding->chain = ctx->chain;
list_add_tail_rcu(&binding->list, &set->bindings); list_add_tail_rcu(&binding->list, &set->bindings);
nft_set_trans_bind(ctx, set); nft_set_trans_bind(ctx, set);
set->use++;
return 0; return 0;
} }
@@ -3825,7 +3838,7 @@ void nf_tables_activate_set(const struct nft_ctx *ctx, struct nft_set *set)
if (nft_set_is_anonymous(set)) if (nft_set_is_anonymous(set))
nft_clear(ctx->net, set); nft_clear(ctx->net, set);
set->use++; nft_use_inc_restore(&set->use);
} }
EXPORT_SYMBOL_GPL(nf_tables_activate_set); EXPORT_SYMBOL_GPL(nf_tables_activate_set);
@@ -3841,17 +3854,17 @@ void nf_tables_deactivate_set(const struct nft_ctx *ctx, struct nft_set *set,
else else
list_del_rcu(&binding->list); list_del_rcu(&binding->list);
set->use--; nft_use_dec(&set->use);
break; break;
case NFT_TRANS_PREPARE: case NFT_TRANS_PREPARE:
if (nft_set_is_anonymous(set)) if (nft_set_is_anonymous(set))
nft_deactivate_next(ctx->net, set); nft_deactivate_next(ctx->net, set);
set->use--; nft_use_dec(&set->use);
return; return;
case NFT_TRANS_ABORT: case NFT_TRANS_ABORT:
case NFT_TRANS_RELEASE: case NFT_TRANS_RELEASE:
set->use--; nft_use_dec(&set->use);
/* fall through */ /* fall through */
default: default:
nf_tables_unbind_set(ctx, set, binding, nf_tables_unbind_set(ctx, set, binding,
@@ -4433,7 +4446,7 @@ void nft_set_elem_destroy(const struct nft_set *set, void *elem,
} }
} }
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF)) if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
(*nft_set_ext_obj(ext))->use--; nft_use_dec(&(*nft_set_ext_obj(ext))->use);
kfree(elem); kfree(elem);
} }
EXPORT_SYMBOL_GPL(nft_set_elem_destroy); EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
@@ -4542,8 +4555,16 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
set->objtype, genmask); set->objtype, genmask);
if (IS_ERR(obj)) { if (IS_ERR(obj)) {
err = PTR_ERR(obj); err = PTR_ERR(obj);
obj = NULL;
goto err2; goto err2;
} }
if (!nft_use_inc(&obj->use)) {
err = -EMFILE;
obj = NULL;
goto err2;
}
nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF); nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF);
} }
@@ -4608,10 +4629,8 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
udata->len = ulen - 1; udata->len = ulen - 1;
nla_memcpy(&udata->data, nla[NFTA_SET_ELEM_USERDATA], ulen); nla_memcpy(&udata->data, nla[NFTA_SET_ELEM_USERDATA], ulen);
} }
if (obj) { if (obj)
*nft_set_ext_obj(ext) = obj; *nft_set_ext_obj(ext) = obj;
obj->use++;
}
trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set); trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set);
if (trans == NULL) if (trans == NULL)
@@ -4657,13 +4676,14 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
err5: err5:
kfree(trans); kfree(trans);
err4: err4:
if (obj)
obj->use--;
kfree(elem.priv); kfree(elem.priv);
err3: err3:
if (nla[NFTA_SET_ELEM_DATA] != NULL) if (nla[NFTA_SET_ELEM_DATA] != NULL)
nft_data_release(&elem.data.val, desc.type); nft_data_release(&elem.data.val, desc.type);
err2: err2:
if (obj)
nft_use_dec_restore(&obj->use);
nft_data_release(&elem.key.val, NFT_DATA_VALUE); nft_data_release(&elem.key.val, NFT_DATA_VALUE);
err1: err1:
return err; return err;
@@ -4723,11 +4743,14 @@ static int nf_tables_newsetelem(struct net *net, struct sock *nlsk,
*/ */
void nft_data_hold(const struct nft_data *data, enum nft_data_types type) void nft_data_hold(const struct nft_data *data, enum nft_data_types type)
{ {
struct nft_chain *chain;
if (type == NFT_DATA_VERDICT) { if (type == NFT_DATA_VERDICT) {
switch (data->verdict.code) { switch (data->verdict.code) {
case NFT_JUMP: case NFT_JUMP:
case NFT_GOTO: case NFT_GOTO:
data->verdict.chain->use++; chain = data->verdict.chain;
nft_use_inc_restore(&chain->use);
break; break;
} }
} }
@@ -4742,7 +4765,7 @@ static void nft_set_elem_activate(const struct net *net,
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA)) if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
nft_data_hold(nft_set_ext_data(ext), set->dtype); nft_data_hold(nft_set_ext_data(ext), set->dtype);
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF)) if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
(*nft_set_ext_obj(ext))->use++; nft_use_inc_restore(&(*nft_set_ext_obj(ext))->use);
} }
static void nft_set_elem_deactivate(const struct net *net, static void nft_set_elem_deactivate(const struct net *net,
@@ -4754,7 +4777,7 @@ static void nft_set_elem_deactivate(const struct net *net,
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA)) if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
nft_data_release(nft_set_ext_data(ext), set->dtype); nft_data_release(nft_set_ext_data(ext), set->dtype);
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF)) if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
(*nft_set_ext_obj(ext))->use--; nft_use_dec(&(*nft_set_ext_obj(ext))->use);
} }
static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
@@ -5151,9 +5174,14 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,
nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla); nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
if (!nft_use_inc(&table->use))
return -EMFILE;
type = nft_obj_type_get(net, objtype); type = nft_obj_type_get(net, objtype);
if (IS_ERR(type)) if (IS_ERR(type)) {
return PTR_ERR(type); err = PTR_ERR(type);
goto err_type;
}
obj = nft_obj_init(&ctx, type, nla[NFTA_OBJ_DATA]); obj = nft_obj_init(&ctx, type, nla[NFTA_OBJ_DATA]);
if (IS_ERR(obj)) { if (IS_ERR(obj)) {
@@ -5174,7 +5202,7 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,
goto err3; goto err3;
list_add_tail_rcu(&obj->list, &table->objects); list_add_tail_rcu(&obj->list, &table->objects);
table->use++;
return 0; return 0;
err3: err3:
kfree(obj->name); kfree(obj->name);
@@ -5184,6 +5212,9 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,
kfree(obj); kfree(obj);
err1: err1:
module_put(type->owner); module_put(type->owner);
err_type:
nft_use_dec_restore(&table->use);
return err; return err;
} }
@@ -5519,6 +5550,22 @@ struct nft_flowtable *nft_flowtable_lookup(const struct nft_table *table,
} }
EXPORT_SYMBOL_GPL(nft_flowtable_lookup); EXPORT_SYMBOL_GPL(nft_flowtable_lookup);
void nf_tables_deactivate_flowtable(const struct nft_ctx *ctx,
struct nft_flowtable *flowtable,
enum nft_trans_phase phase)
{
switch (phase) {
case NFT_TRANS_PREPARE:
case NFT_TRANS_ABORT:
case NFT_TRANS_RELEASE:
nft_use_dec(&flowtable->use);
/* fall through */
default:
return;
}
}
EXPORT_SYMBOL_GPL(nf_tables_deactivate_flowtable);
static struct nft_flowtable * static struct nft_flowtable *
nft_flowtable_lookup_byhandle(const struct nft_table *table, nft_flowtable_lookup_byhandle(const struct nft_table *table,
const struct nlattr *nla, u8 genmask) const struct nlattr *nla, u8 genmask)
@@ -5718,9 +5765,14 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla); nft_ctx_init(&ctx, net, skb, nlh, family, table, NULL, nla);
if (!nft_use_inc(&table->use))
return -EMFILE;
flowtable = kzalloc(sizeof(*flowtable), GFP_KERNEL); flowtable = kzalloc(sizeof(*flowtable), GFP_KERNEL);
if (!flowtable) if (!flowtable) {
return -ENOMEM; err = -ENOMEM;
goto flowtable_alloc;
}
flowtable->table = table; flowtable->table = table;
flowtable->handle = nf_tables_alloc_handle(table); flowtable->handle = nf_tables_alloc_handle(table);
@@ -5774,7 +5826,6 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
goto err6; goto err6;
list_add_tail_rcu(&flowtable->list, &table->flowtables); list_add_tail_rcu(&flowtable->list, &table->flowtables);
table->use++;
return 0; return 0;
err6: err6:
@@ -5792,6 +5843,9 @@ static int nf_tables_newflowtable(struct net *net, struct sock *nlsk,
kfree(flowtable->name); kfree(flowtable->name);
err1: err1:
kfree(flowtable); kfree(flowtable);
flowtable_alloc:
nft_use_dec_restore(&table->use);
return err; return err;
} }
@@ -6666,7 +6720,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
*/ */
if (nft_set_is_anonymous(nft_trans_set(trans)) && if (nft_set_is_anonymous(nft_trans_set(trans)) &&
!list_empty(&nft_trans_set(trans)->bindings)) !list_empty(&nft_trans_set(trans)->bindings))
trans->ctx.table->use--; nft_use_dec(&trans->ctx.table->use);
nf_tables_set_notify(&trans->ctx, nft_trans_set(trans), nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
NFT_MSG_NEWSET, GFP_KERNEL); NFT_MSG_NEWSET, GFP_KERNEL);
@@ -6792,7 +6846,7 @@ static int __nf_tables_abort(struct net *net)
kfree(nft_trans_chain_name(trans)); kfree(nft_trans_chain_name(trans));
nft_trans_destroy(trans); nft_trans_destroy(trans);
} else { } else {
trans->ctx.table->use--; nft_use_dec_restore(&trans->ctx.table->use);
nft_chain_del(trans->ctx.chain); nft_chain_del(trans->ctx.chain);
nf_tables_unregister_hook(trans->ctx.net, nf_tables_unregister_hook(trans->ctx.net,
trans->ctx.table, trans->ctx.table,
@@ -6800,25 +6854,25 @@ static int __nf_tables_abort(struct net *net)
} }
break; break;
case NFT_MSG_DELCHAIN: case NFT_MSG_DELCHAIN:
trans->ctx.table->use++; nft_use_inc_restore(&trans->ctx.table->use);
nft_clear(trans->ctx.net, trans->ctx.chain); nft_clear(trans->ctx.net, trans->ctx.chain);
nft_trans_destroy(trans); nft_trans_destroy(trans);
break; break;
case NFT_MSG_NEWRULE: case NFT_MSG_NEWRULE:
trans->ctx.chain->use--; nft_use_dec_restore(&trans->ctx.chain->use);
list_del_rcu(&nft_trans_rule(trans)->list); list_del_rcu(&nft_trans_rule(trans)->list);
nft_rule_expr_deactivate(&trans->ctx, nft_rule_expr_deactivate(&trans->ctx,
nft_trans_rule(trans), nft_trans_rule(trans),
NFT_TRANS_ABORT); NFT_TRANS_ABORT);
break; break;
case NFT_MSG_DELRULE: case NFT_MSG_DELRULE:
trans->ctx.chain->use++; nft_use_inc_restore(&trans->ctx.chain->use);
nft_clear(trans->ctx.net, nft_trans_rule(trans)); nft_clear(trans->ctx.net, nft_trans_rule(trans));
nft_rule_expr_activate(&trans->ctx, nft_trans_rule(trans)); nft_rule_expr_activate(&trans->ctx, nft_trans_rule(trans));
nft_trans_destroy(trans); nft_trans_destroy(trans);
break; break;
case NFT_MSG_NEWSET: case NFT_MSG_NEWSET:
trans->ctx.table->use--; nft_use_dec_restore(&trans->ctx.table->use);
if (nft_trans_set_bound(trans)) { if (nft_trans_set_bound(trans)) {
nft_trans_destroy(trans); nft_trans_destroy(trans);
break; break;
@@ -6826,7 +6880,7 @@ static int __nf_tables_abort(struct net *net)
list_del_rcu(&nft_trans_set(trans)->list); list_del_rcu(&nft_trans_set(trans)->list);
break; break;
case NFT_MSG_DELSET: case NFT_MSG_DELSET:
trans->ctx.table->use++; nft_use_inc_restore(&trans->ctx.table->use);
nft_clear(trans->ctx.net, nft_trans_set(trans)); nft_clear(trans->ctx.net, nft_trans_set(trans));
nft_trans_destroy(trans); nft_trans_destroy(trans);
break; break;
@@ -6849,22 +6903,22 @@ static int __nf_tables_abort(struct net *net)
nft_trans_destroy(trans); nft_trans_destroy(trans);
break; break;
case NFT_MSG_NEWOBJ: case NFT_MSG_NEWOBJ:
trans->ctx.table->use--; nft_use_dec_restore(&trans->ctx.table->use);
list_del_rcu(&nft_trans_obj(trans)->list); list_del_rcu(&nft_trans_obj(trans)->list);
break; break;
case NFT_MSG_DELOBJ: case NFT_MSG_DELOBJ:
trans->ctx.table->use++; nft_use_inc_restore(&trans->ctx.table->use);
nft_clear(trans->ctx.net, nft_trans_obj(trans)); nft_clear(trans->ctx.net, nft_trans_obj(trans));
nft_trans_destroy(trans); nft_trans_destroy(trans);
break; break;
case NFT_MSG_NEWFLOWTABLE: case NFT_MSG_NEWFLOWTABLE:
trans->ctx.table->use--; nft_use_dec_restore(&trans->ctx.table->use);
list_del_rcu(&nft_trans_flowtable(trans)->list); list_del_rcu(&nft_trans_flowtable(trans)->list);
nft_unregister_flowtable_net_hooks(net, nft_unregister_flowtable_net_hooks(net,
nft_trans_flowtable(trans)); nft_trans_flowtable(trans));
break; break;
case NFT_MSG_DELFLOWTABLE: case NFT_MSG_DELFLOWTABLE:
trans->ctx.table->use++; nft_use_inc_restore(&trans->ctx.table->use);
nft_clear(trans->ctx.net, nft_trans_flowtable(trans)); nft_clear(trans->ctx.net, nft_trans_flowtable(trans));
nft_trans_destroy(trans); nft_trans_destroy(trans);
break; break;
@@ -7278,8 +7332,9 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
return PTR_ERR(chain); return PTR_ERR(chain);
if (nft_is_base_chain(chain)) if (nft_is_base_chain(chain))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!nft_use_inc(&chain->use))
return -EMFILE;
chain->use++;
data->verdict.chain = chain; data->verdict.chain = chain;
break; break;
} }
@@ -7291,10 +7346,13 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
static void nft_verdict_uninit(const struct nft_data *data) static void nft_verdict_uninit(const struct nft_data *data)
{ {
struct nft_chain *chain;
switch (data->verdict.code) { switch (data->verdict.code) {
case NFT_JUMP: case NFT_JUMP:
case NFT_GOTO: case NFT_GOTO:
data->verdict.chain->use--; chain = data->verdict.chain;
nft_use_dec(&chain->use);
break; break;
} }
} }
@@ -7447,11 +7505,11 @@ int __nft_release_basechain(struct nft_ctx *ctx)
nf_tables_unregister_hook(ctx->net, ctx->chain->table, ctx->chain); nf_tables_unregister_hook(ctx->net, ctx->chain->table, ctx->chain);
list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) { list_for_each_entry_safe(rule, nr, &ctx->chain->rules, list) {
list_del(&rule->list); list_del(&rule->list);
ctx->chain->use--; nft_use_dec(&ctx->chain->use);
nf_tables_rule_release(ctx, rule); nf_tables_rule_release(ctx, rule);
} }
nft_chain_del(ctx->chain); nft_chain_del(ctx->chain);
ctx->table->use--; nft_use_dec(&ctx->table->use);
nf_tables_chain_destroy(ctx); nf_tables_chain_destroy(ctx);
return 0; return 0;
@@ -7480,29 +7538,29 @@ static void __nft_release_table(struct net *net, struct nft_table *table)
ctx.chain = chain; ctx.chain = chain;
list_for_each_entry_safe(rule, nr, &chain->rules, list) { list_for_each_entry_safe(rule, nr, &chain->rules, list) {
list_del(&rule->list); list_del(&rule->list);
chain->use--; nft_use_dec(&chain->use);
nf_tables_rule_release(&ctx, rule); nf_tables_rule_release(&ctx, rule);
} }
} }
list_for_each_entry_safe(flowtable, nf, &table->flowtables, list) { list_for_each_entry_safe(flowtable, nf, &table->flowtables, list) {
list_del(&flowtable->list); list_del(&flowtable->list);
table->use--; nft_use_dec(&table->use);
nf_tables_flowtable_destroy(flowtable); nf_tables_flowtable_destroy(flowtable);
} }
list_for_each_entry_safe(set, ns, &table->sets, list) { list_for_each_entry_safe(set, ns, &table->sets, list) {
list_del(&set->list); list_del(&set->list);
table->use--; nft_use_dec(&table->use);
nft_set_destroy(set); nft_set_destroy(set);
} }
list_for_each_entry_safe(obj, ne, &table->objects, list) { list_for_each_entry_safe(obj, ne, &table->objects, list) {
list_del(&obj->list); list_del(&obj->list);
table->use--; nft_use_dec(&table->use);
nft_obj_destroy(&ctx, obj); nft_obj_destroy(&ctx, obj);
} }
list_for_each_entry_safe(chain, nc, &table->chains, list) { list_for_each_entry_safe(chain, nc, &table->chains, list) {
ctx.chain = chain; ctx.chain = chain;
nft_chain_del(chain); nft_chain_del(chain);
table->use--; nft_use_dec(&table->use);
nf_tables_chain_destroy(&ctx); nf_tables_chain_destroy(&ctx);
} }
list_del(&table->list); list_del(&table->list);

View File

@@ -169,12 +169,31 @@ static int nft_flow_offload_init(const struct nft_ctx *ctx,
if (IS_ERR(flowtable)) if (IS_ERR(flowtable))
return PTR_ERR(flowtable); return PTR_ERR(flowtable);
if (!nft_use_inc(&flowtable->use))
return -EMFILE;
priv->flowtable = flowtable; priv->flowtable = flowtable;
flowtable->use++;
return nf_ct_netns_get(ctx->net, ctx->family); return nf_ct_netns_get(ctx->net, ctx->family);
} }
static void nft_flow_offload_deactivate(const struct nft_ctx *ctx,
const struct nft_expr *expr,
enum nft_trans_phase phase)
{
struct nft_flow_offload *priv = nft_expr_priv(expr);
nf_tables_deactivate_flowtable(ctx, priv->flowtable, phase);
}
static void nft_flow_offload_activate(const struct nft_ctx *ctx,
const struct nft_expr *expr)
{
struct nft_flow_offload *priv = nft_expr_priv(expr);
nft_use_inc_restore(&priv->flowtable->use);
}
static void nft_flow_offload_destroy(const struct nft_ctx *ctx, static void nft_flow_offload_destroy(const struct nft_ctx *ctx,
const struct nft_expr *expr) const struct nft_expr *expr)
{ {
@@ -203,6 +222,8 @@ static const struct nft_expr_ops nft_flow_offload_ops = {
.size = NFT_EXPR_SIZE(sizeof(struct nft_flow_offload)), .size = NFT_EXPR_SIZE(sizeof(struct nft_flow_offload)),
.eval = nft_flow_offload_eval, .eval = nft_flow_offload_eval,
.init = nft_flow_offload_init, .init = nft_flow_offload_init,
.activate = nft_flow_offload_activate,
.deactivate = nft_flow_offload_deactivate,
.destroy = nft_flow_offload_destroy, .destroy = nft_flow_offload_destroy,
.validate = nft_flow_offload_validate, .validate = nft_flow_offload_validate,
.dump = nft_flow_offload_dump, .dump = nft_flow_offload_dump,

View File

@@ -43,8 +43,10 @@ static int nft_objref_init(const struct nft_ctx *ctx,
if (IS_ERR(obj)) if (IS_ERR(obj))
return -ENOENT; return -ENOENT;
if (!nft_use_inc(&obj->use))
return -EMFILE;
nft_objref_priv(expr) = obj; nft_objref_priv(expr) = obj;
obj->use++;
return 0; return 0;
} }
@@ -73,7 +75,7 @@ static void nft_objref_deactivate(const struct nft_ctx *ctx,
if (phase == NFT_TRANS_COMMIT) if (phase == NFT_TRANS_COMMIT)
return; return;
obj->use--; nft_use_dec(&obj->use);
} }
static void nft_objref_activate(const struct nft_ctx *ctx, static void nft_objref_activate(const struct nft_ctx *ctx,
@@ -81,7 +83,7 @@ static void nft_objref_activate(const struct nft_ctx *ctx,
{ {
struct nft_object *obj = nft_objref_priv(expr); struct nft_object *obj = nft_objref_priv(expr);
obj->use++; nft_use_inc_restore(&obj->use);
} }
static struct nft_expr_type nft_objref_type; static struct nft_expr_type nft_objref_type;

View File

@@ -370,18 +370,20 @@ static void __packet_set_status(struct packet_sock *po, void *frame, int status)
{ {
union tpacket_uhdr h; union tpacket_uhdr h;
/* WRITE_ONCE() are paired with READ_ONCE() in __packet_get_status */
h.raw = frame; h.raw = frame;
switch (po->tp_version) { switch (po->tp_version) {
case TPACKET_V1: case TPACKET_V1:
h.h1->tp_status = status; WRITE_ONCE(h.h1->tp_status, status);
flush_dcache_page(pgv_to_page(&h.h1->tp_status)); flush_dcache_page(pgv_to_page(&h.h1->tp_status));
break; break;
case TPACKET_V2: case TPACKET_V2:
h.h2->tp_status = status; WRITE_ONCE(h.h2->tp_status, status);
flush_dcache_page(pgv_to_page(&h.h2->tp_status)); flush_dcache_page(pgv_to_page(&h.h2->tp_status));
break; break;
case TPACKET_V3: case TPACKET_V3:
h.h3->tp_status = status; WRITE_ONCE(h.h3->tp_status, status);
flush_dcache_page(pgv_to_page(&h.h3->tp_status)); flush_dcache_page(pgv_to_page(&h.h3->tp_status));
break; break;
default: default:
@@ -398,17 +400,19 @@ static int __packet_get_status(struct packet_sock *po, void *frame)
smp_rmb(); smp_rmb();
/* READ_ONCE() are paired with WRITE_ONCE() in __packet_set_status */
h.raw = frame; h.raw = frame;
switch (po->tp_version) { switch (po->tp_version) {
case TPACKET_V1: case TPACKET_V1:
flush_dcache_page(pgv_to_page(&h.h1->tp_status)); flush_dcache_page(pgv_to_page(&h.h1->tp_status));
return h.h1->tp_status; return READ_ONCE(h.h1->tp_status);
case TPACKET_V2: case TPACKET_V2:
flush_dcache_page(pgv_to_page(&h.h2->tp_status)); flush_dcache_page(pgv_to_page(&h.h2->tp_status));
return h.h2->tp_status; return READ_ONCE(h.h2->tp_status);
case TPACKET_V3: case TPACKET_V3:
flush_dcache_page(pgv_to_page(&h.h3->tp_status)); flush_dcache_page(pgv_to_page(&h.h3->tp_status));
return h.h3->tp_status; return READ_ONCE(h.h3->tp_status);
default: default:
WARN(1, "TPACKET version not supported.\n"); WARN(1, "TPACKET version not supported.\n");
BUG(); BUG();

View File

@@ -748,12 +748,10 @@ static void dist_free(struct disttable *d)
* signed 16 bit values. * signed 16 bit values.
*/ */
static int get_dist_table(struct Qdisc *sch, struct disttable **tbl, static int get_dist_table(struct disttable **tbl, const struct nlattr *attr)
const struct nlattr *attr)
{ {
size_t n = nla_len(attr)/sizeof(__s16); size_t n = nla_len(attr)/sizeof(__s16);
const __s16 *data = nla_data(attr); const __s16 *data = nla_data(attr);
spinlock_t *root_lock;
struct disttable *d; struct disttable *d;
int i; int i;
@@ -768,13 +766,7 @@ static int get_dist_table(struct Qdisc *sch, struct disttable **tbl,
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
d->table[i] = data[i]; d->table[i] = data[i];
root_lock = qdisc_root_sleeping_lock(sch); *tbl = d;
spin_lock_bh(root_lock);
swap(*tbl, d);
spin_unlock_bh(root_lock);
dist_free(d);
return 0; return 0;
} }
@@ -930,6 +922,8 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
{ {
struct netem_sched_data *q = qdisc_priv(sch); struct netem_sched_data *q = qdisc_priv(sch);
struct nlattr *tb[TCA_NETEM_MAX + 1]; struct nlattr *tb[TCA_NETEM_MAX + 1];
struct disttable *delay_dist = NULL;
struct disttable *slot_dist = NULL;
struct tc_netem_qopt *qopt; struct tc_netem_qopt *qopt;
struct clgstate old_clg; struct clgstate old_clg;
int old_loss_model = CLG_RANDOM; int old_loss_model = CLG_RANDOM;
@@ -943,6 +937,18 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
if (ret < 0) if (ret < 0)
return ret; return ret;
if (tb[TCA_NETEM_DELAY_DIST]) {
ret = get_dist_table(&delay_dist, tb[TCA_NETEM_DELAY_DIST]);
if (ret)
goto table_free;
}
if (tb[TCA_NETEM_SLOT_DIST]) {
ret = get_dist_table(&slot_dist, tb[TCA_NETEM_SLOT_DIST]);
if (ret)
goto table_free;
}
sch_tree_lock(sch); sch_tree_lock(sch);
/* backup q->clg and q->loss_model */ /* backup q->clg and q->loss_model */
old_clg = q->clg; old_clg = q->clg;
@@ -952,26 +958,17 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
ret = get_loss_clg(q, tb[TCA_NETEM_LOSS]); ret = get_loss_clg(q, tb[TCA_NETEM_LOSS]);
if (ret) { if (ret) {
q->loss_model = old_loss_model; q->loss_model = old_loss_model;
q->clg = old_clg;
goto unlock; goto unlock;
} }
} else { } else {
q->loss_model = CLG_RANDOM; q->loss_model = CLG_RANDOM;
} }
if (tb[TCA_NETEM_DELAY_DIST]) { if (delay_dist)
ret = get_dist_table(sch, &q->delay_dist, swap(q->delay_dist, delay_dist);
tb[TCA_NETEM_DELAY_DIST]); if (slot_dist)
if (ret) swap(q->slot_dist, slot_dist);
goto get_table_failure;
}
if (tb[TCA_NETEM_SLOT_DIST]) {
ret = get_dist_table(sch, &q->slot_dist,
tb[TCA_NETEM_SLOT_DIST]);
if (ret)
goto get_table_failure;
}
sch->limit = qopt->limit; sch->limit = qopt->limit;
q->latency = PSCHED_TICKS2NS(qopt->latency); q->latency = PSCHED_TICKS2NS(qopt->latency);
@@ -1021,17 +1018,11 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,
unlock: unlock:
sch_tree_unlock(sch); sch_tree_unlock(sch);
table_free:
dist_free(delay_dist);
dist_free(slot_dist);
return ret; return ret;
get_table_failure:
/* recover clg and loss_model, in case of
* q->clg and q->loss_model were modified
* in get_loss_clg()
*/
q->clg = old_clg;
q->loss_model = old_loss_model;
goto unlock;
} }
static int netem_init(struct Qdisc *sch, struct nlattr *opt, static int netem_init(struct Qdisc *sch, struct nlattr *opt,

View File

@@ -198,7 +198,7 @@ void regression1_test(void)
nr_threads = 2; nr_threads = 2;
pthread_barrier_init(&worker_barrier, NULL, nr_threads); pthread_barrier_init(&worker_barrier, NULL, nr_threads);
threads = malloc(nr_threads * sizeof(pthread_t *)); threads = malloc(nr_threads * sizeof(*threads));
for (i = 0; i < nr_threads; i++) { for (i = 0; i < nr_threads; i++) {
arg = i; arg = i;