From a1706ac4c0201ea0143dc0db0659001b26ceeabb Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 30 May 2011 07:42:51 +0200 Subject: Revert "block: Remove extra discard_alignment from hd_struct." It was not a good idea to start dereferencing disk->queue from the fs sysfs strategy for displaying discard alignment. We ran into first a NULL pointer deref, and after fixing that we sometimes see unvalid disk->queue pointer values. Since discard is the only one of the bunch actually looking into the queue, just revert the change. This reverts commit 23ceb5b7719e9276d4fa72a3ecf94dd396755276. Conflicts: fs/partitions/check.c --- include/linux/genhd.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/genhd.h b/include/linux/genhd.h index b78956b3c2e7..300d7582006e 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -100,6 +100,7 @@ struct hd_struct { sector_t start_sect; sector_t nr_sects; sector_t alignment_offset; + unsigned int discard_alignment; struct device __dev; struct kobject *holder_dir; int policy, partno; -- cgit v1.2.3 From ea9d6553b3b3044e7374774cc33bb1b2eee19dd3 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 31 May 2011 13:45:53 +0200 Subject: block: remove unwanted semicolons Since those defined functions require additional semicolon from the caller, they could cause potential syntax errors when used in if-else statements. Signed-off-by: Namhyung Kim Acked-by: Martin K. Petersen Signed-off-by: Jens Axboe --- include/linux/blkdev.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'include/linux') diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index ae9091a68480..1a23722e8878 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1282,8 +1282,8 @@ queue_max_integrity_segments(struct request_queue *q) #define blk_get_integrity(a) (0) #define blk_integrity_compare(a, b) (0) #define blk_integrity_register(a, b) (0) -#define blk_integrity_unregister(a) do { } while (0); -#define blk_queue_max_integrity_segments(a, b) do { } while (0); +#define blk_integrity_unregister(a) do { } while (0) +#define blk_queue_max_integrity_segments(a, b) do { } while (0) #define queue_max_integrity_segments(a) (0) #define blk_integrity_merge_rq(a, b, c) (0) #define blk_integrity_merge_bio(a, b, c) (0) -- cgit v1.2.3 From 333ba7325213f0a09dfa5ceeddb056d6ad74b3b5 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Sun, 29 May 2011 15:53:20 +0300 Subject: cfg80211: don't drop p2p probe responses Commit 0a35d36 ("cfg80211: Use capability info to detect mesh beacons") assumed that probe response with both ESS and IBSS bits cleared means that the frame was sent by a mesh sta. However, these capabilities are also being used in the p2p_find phase, and the mesh-validation broke it. Rename the WLAN_CAPABILITY_IS_MBSS macro, and verify that mesh ies exist before assuming this frame was sent by a mesh sta. Signed-off-by: Eliad Peller Signed-off-by: John W. Linville --- include/linux/ieee80211.h | 8 ++++++-- net/wireless/scan.c | 43 ++++++++++++++++++++++++------------------- 2 files changed, 30 insertions(+), 21 deletions(-) (limited to 'include/linux') diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index b2eee5879883..bf56b6f78270 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -1003,8 +1003,12 @@ struct ieee80211_ht_info { #define WLAN_CAPABILITY_ESS (1<<0) #define WLAN_CAPABILITY_IBSS (1<<1) -/* A mesh STA sets the ESS and IBSS capability bits to zero */ -#define WLAN_CAPABILITY_IS_MBSS(cap) \ +/* + * A mesh STA sets the ESS and IBSS capability bits to zero. + * however, this holds true for p2p probe responses (in the p2p_find + * phase) as well. + */ +#define WLAN_CAPABILITY_IS_STA_BSS(cap) \ (!((cap) & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS))) #define WLAN_CAPABILITY_CF_POLLABLE (1<<2) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 73a441d237b5..7a6c67667d70 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -267,13 +267,35 @@ static bool is_bss(struct cfg80211_bss *a, return memcmp(ssidie + 2, ssid, ssid_len) == 0; } +static bool is_mesh_bss(struct cfg80211_bss *a) +{ + const u8 *ie; + + if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability)) + return false; + + ie = cfg80211_find_ie(WLAN_EID_MESH_ID, + a->information_elements, + a->len_information_elements); + if (!ie) + return false; + + ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, + a->information_elements, + a->len_information_elements); + if (!ie) + return false; + + return true; +} + static bool is_mesh(struct cfg80211_bss *a, const u8 *meshid, size_t meshidlen, const u8 *meshcfg) { const u8 *ie; - if (!WLAN_CAPABILITY_IS_MBSS(a->capability)) + if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability)) return false; ie = cfg80211_find_ie(WLAN_EID_MESH_ID, @@ -311,7 +333,7 @@ static int cmp_bss(struct cfg80211_bss *a, if (a->channel != b->channel) return b->channel->center_freq - a->channel->center_freq; - if (WLAN_CAPABILITY_IS_MBSS(a->capability | b->capability)) { + if (is_mesh_bss(a) && is_mesh_bss(b)) { r = cmp_ies(WLAN_EID_MESH_ID, a->information_elements, a->len_information_elements, @@ -457,7 +479,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, struct cfg80211_internal_bss *res) { struct cfg80211_internal_bss *found = NULL; - const u8 *meshid, *meshcfg; /* * The reference to "res" is donated to this function. @@ -470,22 +491,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev, res->ts = jiffies; - if (WLAN_CAPABILITY_IS_MBSS(res->pub.capability)) { - /* must be mesh, verify */ - meshid = cfg80211_find_ie(WLAN_EID_MESH_ID, - res->pub.information_elements, - res->pub.len_information_elements); - meshcfg = cfg80211_find_ie(WLAN_EID_MESH_CONFIG, - res->pub.information_elements, - res->pub.len_information_elements); - if (!meshid || !meshcfg || - meshcfg[1] != sizeof(struct ieee80211_meshconf_ie)) { - /* bogus mesh */ - kref_put(&res->ref, bss_release); - return NULL; - } - } - spin_lock_bh(&dev->bss_lock); found = rb_find_bss(dev, res); -- cgit v1.2.3 From a3bcc23e890a6d49d6763d9eb073d711de2e0469 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Wed, 1 Jun 2011 06:49:10 +0000 Subject: af-packet: Add flag to distinguish VID 0 from no-vlan. Currently, user-space cannot determine if a 0 tcp_vlan_tci means there is no VLAN tag or the VLAN ID was zero. Add flag to make this explicit. User-space can check for TP_STATUS_VLAN_VALID || tp_vlan_tci > 0, which will be backwards compatible. Older could would have just checked for tp_vlan_tci, so it will work no worse than before. Signed-off-by: Ben Greear Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- include/linux/if_packet.h | 1 + net/packet/af_packet.c | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/include/linux/if_packet.h b/include/linux/if_packet.h index 72bfa5a034dd..6d66ce1791a9 100644 --- a/include/linux/if_packet.h +++ b/include/linux/if_packet.h @@ -70,6 +70,7 @@ struct tpacket_auxdata { #define TP_STATUS_COPY 0x2 #define TP_STATUS_LOSING 0x4 #define TP_STATUS_CSUMNOTREADY 0x8 +#define TP_STATUS_VLAN_VALID 0x10 /* auxdata has valid tp_vlan_tci */ /* Tx ring - header status */ #define TP_STATUS_AVAILABLE 0x0 diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 925f715686a5..ba248d93399a 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -798,7 +798,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev, getnstimeofday(&ts); h.h2->tp_sec = ts.tv_sec; h.h2->tp_nsec = ts.tv_nsec; - h.h2->tp_vlan_tci = vlan_tx_tag_get(skb); + if (vlan_tx_tag_present(skb)) { + h.h2->tp_vlan_tci = vlan_tx_tag_get(skb); + status |= TP_STATUS_VLAN_VALID; + } else { + h.h2->tp_vlan_tci = 0; + } hdrlen = sizeof(*h.h2); break; default: @@ -1725,8 +1730,12 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock, aux.tp_snaplen = skb->len; aux.tp_mac = 0; aux.tp_net = skb_network_offset(skb); - aux.tp_vlan_tci = vlan_tx_tag_get(skb); - + if (vlan_tx_tag_present(skb)) { + aux.tp_vlan_tci = vlan_tx_tag_get(skb); + aux.tp_status |= TP_STATUS_VLAN_VALID; + } else { + aux.tp_vlan_tci = 0; + } put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux); } -- cgit v1.2.3 From 55db4c64eddf37e31279ec15fe90314713bc9cfa Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 4 Jun 2011 06:33:24 +0900 Subject: Revert "tty: make receive_buf() return the amout of bytes received" This reverts commit b1c43f82c5aa265442f82dba31ce985ebb7aa71c. It was broken in so many ways, and results in random odd pty issues. It re-introduced the buggy schedule_work() in flush_to_ldisc() that can cause endless work-loops (see commit a5660b41af6a: "tty: fix endless work loop when the buffer fills up"). It also used an "unsigned int" return value fo the ->receive_buf() function, but then made multiple functions return a negative error code, and didn't actually check for the error in the caller. And it didn't actually work at all. BenH bisected down odd tty behavior to it: "It looks like the patch is causing some major malfunctions of the X server for me, possibly related to PTYs. For example, cat'ing a large file in a gnome terminal hangs the kernel for -minutes- in a loop of what looks like flush_to_ldisc/workqueue code, (some ftrace data in the quoted bits further down). ... Some more data: It -looks- like what happens is that the flush_to_ldisc work queue entry constantly re-queues itself (because the PTY is full ?) and the workqueue thread will basically loop forver calling it without ever scheduling, thus starving the consumer process that could have emptied the PTY." which is pretty much exactly the problem we fixed in a5660b41af6a. Milton Miller pointed out the 'unsigned int' issue. Reported-by: Benjamin Herrenschmidt Reported-by: Milton Miller Cc: Stefan Bigler Cc: Toby Gray Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: Alan Cox Signed-off-by: Linus Torvalds --- drivers/bluetooth/hci_ldisc.c | 17 ++++------- drivers/input/serio/serport.c | 10 ++----- drivers/isdn/gigaset/ser-gigaset.c | 8 ++--- drivers/misc/ti-st/st_core.c | 6 ++-- drivers/net/caif/caif_serial.c | 6 ++-- drivers/net/can/slcan.c | 9 ++---- drivers/net/hamradio/6pack.c | 8 ++--- drivers/net/hamradio/mkiss.c | 11 +++---- drivers/net/irda/irtty-sir.c | 16 +++++----- drivers/net/ppp_async.c | 6 ++-- drivers/net/ppp_synctty.c | 6 ++-- drivers/net/slip.c | 11 +++---- drivers/net/wan/x25_asy.c | 7 ++--- drivers/tty/n_gsm.c | 6 ++-- drivers/tty/n_hdlc.c | 18 +++++------ drivers/tty/n_r3964.c | 10 +++---- drivers/tty/n_tty.c | 61 +++++++++++++++++++++++++++++--------- drivers/tty/tty_buffer.c | 15 ++++------ drivers/tty/vt/selection.c | 3 +- include/linux/tty_ldisc.h | 9 +++--- 20 files changed, 115 insertions(+), 128 deletions(-) (limited to 'include/linux') diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index b3f01996318f..48ad2a7ab080 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -355,29 +355,24 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty) * flags pointer to flags for data * count count of received data in bytes * - * Return Value: Number of bytes received + * Return Value: None */ -static unsigned int hci_uart_tty_receive(struct tty_struct *tty, - const u8 *data, char *flags, int count) +static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count) { struct hci_uart *hu = (void *)tty->disc_data; - int received; if (!hu || tty != hu->tty) - return -ENODEV; + return; if (!test_bit(HCI_UART_PROTO_SET, &hu->flags)) - return -EINVAL; + return; spin_lock(&hu->rx_lock); - received = hu->proto->recv(hu, (void *) data, count); - if (received > 0) - hu->hdev->stat.byte_rx += received; + hu->proto->recv(hu, (void *) data, count); + hu->hdev->stat.byte_rx += count; spin_unlock(&hu->rx_lock); tty_unthrottle(tty); - - return received; } static int hci_uart_register_dev(struct hci_uart *hu) diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index f3698967edf6..8755f5f3ad37 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -120,21 +120,17 @@ static void serport_ldisc_close(struct tty_struct *tty) * 'interrupt' routine. */ -static unsigned int serport_ldisc_receive(struct tty_struct *tty, - const unsigned char *cp, char *fp, int count) +static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { struct serport *serport = (struct serport*) tty->disc_data; unsigned long flags; unsigned int ch_flags; - int ret = 0; int i; spin_lock_irqsave(&serport->lock, flags); - if (!test_bit(SERPORT_ACTIVE, &serport->flags)) { - ret = -EINVAL; + if (!test_bit(SERPORT_ACTIVE, &serport->flags)) goto out; - } for (i = 0; i < count; i++) { switch (fp[i]) { @@ -156,8 +152,6 @@ static unsigned int serport_ldisc_receive(struct tty_struct *tty, out: spin_unlock_irqrestore(&serport->lock, flags); - - return ret == 0 ? count : ret; } /* diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c index 1d44d470897c..86a5c4f7775e 100644 --- a/drivers/isdn/gigaset/ser-gigaset.c +++ b/drivers/isdn/gigaset/ser-gigaset.c @@ -674,7 +674,7 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file, * cflags buffer containing error flags for received characters (ignored) * count number of received characters */ -static unsigned int +static void gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf, char *cflags, int count) { @@ -683,12 +683,12 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf, struct inbuf_t *inbuf; if (!cs) - return -ENODEV; + return; inbuf = cs->inbuf; if (!inbuf) { dev_err(cs->dev, "%s: no inbuf\n", __func__); cs_put(cs); - return -EINVAL; + return; } tail = inbuf->tail; @@ -725,8 +725,6 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf, gig_dbg(DEBUG_INTR, "%s-->BH", __func__); gigaset_schedule_event(cs); cs_put(cs); - - return count; } /* diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index 1a05fe08e2cb..f91f82eabda7 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -747,8 +747,8 @@ static void st_tty_close(struct tty_struct *tty) pr_debug("%s: done ", __func__); } -static unsigned int st_tty_receive(struct tty_struct *tty, - const unsigned char *data, char *tty_flags, int count) +static void st_tty_receive(struct tty_struct *tty, const unsigned char *data, + char *tty_flags, int count) { #ifdef VERBOSE print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE, @@ -761,8 +761,6 @@ static unsigned int st_tty_receive(struct tty_struct *tty, */ st_recv(tty->disc_data, data, count); pr_debug("done %s", __func__); - - return count; } /* wake-up function called in from the TTY layer diff --git a/drivers/net/caif/caif_serial.c b/drivers/net/caif/caif_serial.c index 73c7e03617ec..3df0c0f8b8bf 100644 --- a/drivers/net/caif/caif_serial.c +++ b/drivers/net/caif/caif_serial.c @@ -167,8 +167,8 @@ static inline void debugfs_tx(struct ser_device *ser, const u8 *data, int size) #endif -static unsigned int ldisc_receive(struct tty_struct *tty, - const u8 *data, char *flags, int count) +static void ldisc_receive(struct tty_struct *tty, const u8 *data, + char *flags, int count) { struct sk_buff *skb = NULL; struct ser_device *ser; @@ -215,8 +215,6 @@ static unsigned int ldisc_receive(struct tty_struct *tty, } else ++ser->dev->stats.rx_dropped; update_tty_status(ser); - - return count; } static int handle_tx(struct ser_device *ser) diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c index 75622d54581f..1b49df6b2470 100644 --- a/drivers/net/can/slcan.c +++ b/drivers/net/can/slcan.c @@ -425,17 +425,16 @@ static void slc_setup(struct net_device *dev) * in parallel */ -static unsigned int slcan_receive_buf(struct tty_struct *tty, +static void slcan_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { struct slcan *sl = (struct slcan *) tty->disc_data; - int bytes = count; if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev)) - return -ENODEV; + return; /* Read the characters out of the buffer */ - while (bytes--) { + while (count--) { if (fp && *fp++) { if (!test_and_set_bit(SLF_ERROR, &sl->flags)) sl->dev->stats.rx_errors++; @@ -444,8 +443,6 @@ static unsigned int slcan_receive_buf(struct tty_struct *tty, } slcan_unesc(sl, *cp++); } - - return count; } /************************************ diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 992089639ea4..3e5d0b6b6516 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -456,7 +456,7 @@ out: * a block of 6pack data has been received, which can now be decapsulated * and sent on to some IP layer for further processing. */ -static unsigned int sixpack_receive_buf(struct tty_struct *tty, +static void sixpack_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { struct sixpack *sp; @@ -464,11 +464,11 @@ static unsigned int sixpack_receive_buf(struct tty_struct *tty, int count1; if (!count) - return 0; + return; sp = sp_get(tty); if (!sp) - return -ENODEV; + return; memcpy(buf, cp, count < sizeof(buf) ? count : sizeof(buf)); @@ -487,8 +487,6 @@ static unsigned int sixpack_receive_buf(struct tty_struct *tty, sp_put(sp); tty_unthrottle(tty); - - return count1; } /* diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 0e4f23531140..4c628393c8b1 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -923,14 +923,13 @@ static long mkiss_compat_ioctl(struct tty_struct *tty, struct file *file, * a block of data has been received, which can now be decapsulated * and sent on to the AX.25 layer for further processing. */ -static unsigned int mkiss_receive_buf(struct tty_struct *tty, - const unsigned char *cp, char *fp, int count) +static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) { struct mkiss *ax = mkiss_get(tty); - int bytes = count; if (!ax) - return -ENODEV; + return; /* * Argh! mtu change time! - costs us the packet part received @@ -940,7 +939,7 @@ static unsigned int mkiss_receive_buf(struct tty_struct *tty, ax_changedmtu(ax); /* Read the characters out of the buffer */ - while (bytes--) { + while (count--) { if (fp != NULL && *fp++) { if (!test_and_set_bit(AXF_ERROR, &ax->flags)) ax->dev->stats.rx_errors++; @@ -953,8 +952,6 @@ static unsigned int mkiss_receive_buf(struct tty_struct *tty, mkiss_put(ax); tty_unthrottle(tty); - - return count; } /* diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index 035861d8acb1..3352b2443e58 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -216,23 +216,23 @@ static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t * usbserial: urb-complete-interrupt / softint */ -static unsigned int irtty_receive_buf(struct tty_struct *tty, - const unsigned char *cp, char *fp, int count) +static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) { struct sir_dev *dev; struct sirtty_cb *priv = tty->disc_data; int i; - IRDA_ASSERT(priv != NULL, return -ENODEV;); - IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -EINVAL;); + IRDA_ASSERT(priv != NULL, return;); + IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;); if (unlikely(count==0)) /* yes, this happens */ - return 0; + return; dev = priv->dev; if (!dev) { IRDA_WARNING("%s(), not ready yet!\n", __func__); - return -ENODEV; + return; } for (i = 0; i < count; i++) { @@ -242,13 +242,11 @@ static unsigned int irtty_receive_buf(struct tty_struct *tty, if (fp && *fp++) { IRDA_DEBUG(0, "Framing or parity error!\n"); sirdev_receive(dev, NULL, 0); /* notify sir_dev (updating stats) */ - return -EINVAL; + return; } } sirdev_receive(dev, cp, count); - - return count; } /* diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index 53872d7d7382..a1b82c9c67d2 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -340,7 +340,7 @@ ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait) } /* May sleep, don't call from interrupt level or with interrupts disabled */ -static unsigned int +static void ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf, char *cflags, int count) { @@ -348,7 +348,7 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf, unsigned long flags; if (!ap) - return -ENODEV; + return; spin_lock_irqsave(&ap->recv_lock, flags); ppp_async_input(ap, buf, cflags, count); spin_unlock_irqrestore(&ap->recv_lock, flags); @@ -356,8 +356,6 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf, tasklet_schedule(&ap->tsk); ap_put(ap); tty_unthrottle(tty); - - return count; } static void diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index 0815790a5cf9..2573f525f11c 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -381,7 +381,7 @@ ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait) } /* May sleep, don't call from interrupt level or with interrupts disabled */ -static unsigned int +static void ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf, char *cflags, int count) { @@ -389,7 +389,7 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf, unsigned long flags; if (!ap) - return -ENODEV; + return; spin_lock_irqsave(&ap->recv_lock, flags); ppp_sync_input(ap, buf, cflags, count); spin_unlock_irqrestore(&ap->recv_lock, flags); @@ -397,8 +397,6 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf, tasklet_schedule(&ap->tsk); sp_put(ap); tty_unthrottle(tty); - - return count; } static void diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 584809c656d5..8ec1a9a0bb9a 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -670,17 +670,16 @@ static void sl_setup(struct net_device *dev) * in parallel */ -static unsigned int slip_receive_buf(struct tty_struct *tty, - const unsigned char *cp, char *fp, int count) +static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) { struct slip *sl = tty->disc_data; - int bytes = count; if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev)) - return -ENODEV; + return; /* Read the characters out of the buffer */ - while (bytes--) { + while (count--) { if (fp && *fp++) { if (!test_and_set_bit(SLF_ERROR, &sl->flags)) sl->dev->stats.rx_errors++; @@ -694,8 +693,6 @@ static unsigned int slip_receive_buf(struct tty_struct *tty, #endif slip_unesc(sl, *cp++); } - - return count; } /************************************ diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 40398bf7d036..24297b274cd4 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -517,18 +517,17 @@ static int x25_asy_close(struct net_device *dev) * and sent on to some IP layer for further processing. */ -static unsigned int x25_asy_receive_buf(struct tty_struct *tty, +static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { struct x25_asy *sl = tty->disc_data; - int bytes = count; if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev)) return; /* Read the characters out of the buffer */ - while (bytes--) { + while (count--) { if (fp && *fp++) { if (!test_and_set_bit(SLF_ERROR, &sl->flags)) sl->dev->stats.rx_errors++; @@ -537,8 +536,6 @@ static unsigned int x25_asy_receive_buf(struct tty_struct *tty, } x25_asy_unesc(sl, *cp++); } - - return count; } /* diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index a4c42a75a3bf..09e8c7d53af3 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2128,8 +2128,8 @@ static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm) gsm->tty = NULL; } -static unsigned int gsmld_receive_buf(struct tty_struct *tty, - const unsigned char *cp, char *fp, int count) +static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) { struct gsm_mux *gsm = tty->disc_data; const unsigned char *dp; @@ -2162,8 +2162,6 @@ static unsigned int gsmld_receive_buf(struct tty_struct *tty, } /* FASYNC if needed ? */ /* If clogged call tty_throttle(tty); */ - - return count; } /** diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index cac666314aef..cea56033b34c 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -188,8 +188,8 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait); static int n_hdlc_tty_open(struct tty_struct *tty); static void n_hdlc_tty_close(struct tty_struct *tty); -static unsigned int n_hdlc_tty_receive(struct tty_struct *tty, - const __u8 *cp, char *fp, int count); +static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp, + char *fp, int count); static void n_hdlc_tty_wakeup(struct tty_struct *tty); #define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f))) @@ -509,8 +509,8 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty) * Called by tty low level driver when receive data is available. Data is * interpreted as one HDLC frame. */ -static unsigned int n_hdlc_tty_receive(struct tty_struct *tty, - const __u8 *data, char *flags, int count) +static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, + char *flags, int count) { register struct n_hdlc *n_hdlc = tty2n_hdlc (tty); register struct n_hdlc_buf *buf; @@ -521,20 +521,20 @@ static unsigned int n_hdlc_tty_receive(struct tty_struct *tty, /* This can happen if stuff comes in on the backup tty */ if (!n_hdlc || tty != n_hdlc->tty) - return -ENODEV; + return; /* verify line is using HDLC discipline */ if (n_hdlc->magic != HDLC_MAGIC) { printk("%s(%d) line not using HDLC discipline\n", __FILE__,__LINE__); - return -EINVAL; + return; } if ( count>maxframe ) { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d) rx count>maxframesize, data discarded\n", __FILE__,__LINE__); - return -EINVAL; + return; } /* get a free HDLC buffer */ @@ -550,7 +550,7 @@ static unsigned int n_hdlc_tty_receive(struct tty_struct *tty, if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d) no more rx buffers, data discarded\n", __FILE__,__LINE__); - return -EINVAL; + return; } /* copy received data to HDLC buffer */ @@ -565,8 +565,6 @@ static unsigned int n_hdlc_tty_receive(struct tty_struct *tty, if (n_hdlc->tty->fasync != NULL) kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN); - return count; - } /* end of n_hdlc_tty_receive() */ /** diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index a4bc39c21a43..5c6c31459a2f 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -139,8 +139,8 @@ static int r3964_ioctl(struct tty_struct *tty, struct file *file, static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old); static unsigned int r3964_poll(struct tty_struct *tty, struct file *file, struct poll_table_struct *wait); -static unsigned int r3964_receive_buf(struct tty_struct *tty, - const unsigned char *cp, char *fp, int count); +static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count); static struct tty_ldisc_ops tty_ldisc_N_R3964 = { .owner = THIS_MODULE, @@ -1239,8 +1239,8 @@ static unsigned int r3964_poll(struct tty_struct *tty, struct file *file, return result; } -static unsigned int r3964_receive_buf(struct tty_struct *tty, - const unsigned char *cp, char *fp, int count) +static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) { struct r3964_info *pInfo = tty->disc_data; const unsigned char *p; @@ -1257,8 +1257,6 @@ static unsigned int r3964_receive_buf(struct tty_struct *tty, } } - - return count; } MODULE_LICENSE("GPL"); diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 95d0a9c2dd13..0ad32888091c 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -81,6 +81,38 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x, return put_user(x, ptr); } +/** + * n_tty_set__room - receive space + * @tty: terminal + * + * Called by the driver to find out how much data it is + * permitted to feed to the line discipline without any being lost + * and thus to manage flow control. Not serialized. Answers for the + * "instant". + */ + +static void n_tty_set_room(struct tty_struct *tty) +{ + /* tty->read_cnt is not read locked ? */ + int left = N_TTY_BUF_SIZE - tty->read_cnt - 1; + int old_left; + + /* + * If we are doing input canonicalization, and there are no + * pending newlines, let characters through without limit, so + * that erase characters will be handled. Other excess + * characters will be beeped. + */ + if (left <= 0) + left = tty->icanon && !tty->canon_data; + old_left = tty->receive_room; + tty->receive_room = left; + + /* Did this open up the receive buffer? We may need to flip */ + if (left && !old_left) + schedule_work(&tty->buf.work); +} + static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty) { if (tty->read_cnt < N_TTY_BUF_SIZE) { @@ -152,6 +184,7 @@ static void reset_buffer_flags(struct tty_struct *tty) tty->canon_head = tty->canon_data = tty->erasing = 0; memset(&tty->read_flags, 0, sizeof tty->read_flags); + n_tty_set_room(tty); check_unthrottle(tty); } @@ -1327,19 +1360,17 @@ static void n_tty_write_wakeup(struct tty_struct *tty) * calls one at a time and in order (or using flush_to_ldisc) */ -static unsigned int n_tty_receive_buf(struct tty_struct *tty, - const unsigned char *cp, char *fp, int count) +static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, + char *fp, int count) { const unsigned char *p; char *f, flags = TTY_NORMAL; int i; char buf[64]; unsigned long cpuflags; - int left; - int ret = 0; if (!tty->read_buf) - return 0; + return; if (tty->real_raw) { spin_lock_irqsave(&tty->read_lock, cpuflags); @@ -1349,7 +1380,6 @@ static unsigned int n_tty_receive_buf(struct tty_struct *tty, memcpy(tty->read_buf + tty->read_head, cp, i); tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1); tty->read_cnt += i; - ret += i; cp += i; count -= i; @@ -1359,10 +1389,8 @@ static unsigned int n_tty_receive_buf(struct tty_struct *tty, memcpy(tty->read_buf + tty->read_head, cp, i); tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1); tty->read_cnt += i; - ret += i; spin_unlock_irqrestore(&tty->read_lock, cpuflags); } else { - ret = count; for (i = count, p = cp, f = fp; i; i--, p++) { if (f) flags = *f++; @@ -1390,6 +1418,8 @@ static unsigned int n_tty_receive_buf(struct tty_struct *tty, tty->ops->flush_chars(tty); } + n_tty_set_room(tty); + if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) || L_EXTPROC(tty)) { kill_fasync(&tty->fasync, SIGIO, POLL_IN); @@ -1402,12 +1432,8 @@ static unsigned int n_tty_receive_buf(struct tty_struct *tty, * mode. We don't want to throttle the driver if we're in * canonical mode and don't have a newline yet! */ - left = N_TTY_BUF_SIZE - tty->read_cnt - 1; - - if (left < TTY_THRESHOLD_THROTTLE) + if (tty->receive_room < TTY_THRESHOLD_THROTTLE) tty_throttle(tty); - - return ret; } int is_ignored(int sig) @@ -1451,6 +1477,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { tty->raw = 1; tty->real_raw = 1; + n_tty_set_room(tty); return; } if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) || @@ -1503,6 +1530,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) else tty->real_raw = 0; } + n_tty_set_room(tty); /* The termios change make the tty ready for I/O */ wake_up_interruptible(&tty->write_wait); wake_up_interruptible(&tty->read_wait); @@ -1784,6 +1812,8 @@ do_it_again: retval = -ERESTARTSYS; break; } + /* FIXME: does n_tty_set_room need locking ? */ + n_tty_set_room(tty); timeout = schedule_timeout(timeout); continue; } @@ -1855,8 +1885,10 @@ do_it_again: * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode, * we won't get any more characters. */ - if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) + if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) { + n_tty_set_room(tty); check_unthrottle(tty); + } if (b - buf >= minimum) break; @@ -1878,6 +1910,7 @@ do_it_again: } else if (test_and_clear_bit(TTY_PUSH, &tty->flags)) goto do_it_again; + n_tty_set_room(tty); return retval; } diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 46de2e075dac..f1a7918d71aa 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -416,7 +416,6 @@ static void flush_to_ldisc(struct work_struct *work) struct tty_buffer *head, *tail = tty->buf.tail; int seen_tail = 0; while ((head = tty->buf.head) != NULL) { - int copied; int count; char *char_buf; unsigned char *flag_buf; @@ -443,19 +442,17 @@ static void flush_to_ldisc(struct work_struct *work) line discipline as we want to empty the queue */ if (test_bit(TTY_FLUSHPENDING, &tty->flags)) break; + if (!tty->receive_room || seen_tail) + break; + if (count > tty->receive_room) + count = tty->receive_room; char_buf = head->char_buf_ptr + head->read; flag_buf = head->flag_buf_ptr + head->read; + head->read += count; spin_unlock_irqrestore(&tty->buf.lock, flags); - copied = disc->ops->receive_buf(tty, char_buf, + disc->ops->receive_buf(tty, char_buf, flag_buf, count); spin_lock_irqsave(&tty->buf.lock, flags); - - head->read += copied; - - if (copied == 0 || seen_tail) { - schedule_work(&tty->buf.work); - break; - } } clear_bit(TTY_FLUSHING, &tty->flags); } diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 67b1d0d7c8ac..fb864e7fcd13 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -332,7 +332,8 @@ int paste_selection(struct tty_struct *tty) continue; } count = sel_buffer_lth - pasted; - count = tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted, + count = min(count, tty->receive_room); + tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted, NULL, count); pasted += count; } diff --git a/include/linux/tty_ldisc.h b/include/linux/tty_ldisc.h index 5b07792ccb46..ff7dc08696a8 100644 --- a/include/linux/tty_ldisc.h +++ b/include/linux/tty_ldisc.h @@ -76,7 +76,7 @@ * tty device. It is solely the responsibility of the line * discipline to handle poll requests. * - * unsigned int (*receive_buf)(struct tty_struct *, const unsigned char *cp, + * void (*receive_buf)(struct tty_struct *, const unsigned char *cp, * char *fp, int count); * * This function is called by the low-level tty driver to send @@ -84,8 +84,7 @@ * processing. is a pointer to the buffer of input * character received by the device. is a pointer to a * pointer of flag bytes which indicate whether a character was - * received with a parity error, etc. Returns the amount of bytes - * received. + * received with a parity error, etc. * * void (*write_wakeup)(struct tty_struct *); * @@ -141,8 +140,8 @@ struct tty_ldisc_ops { /* * The following routines are called from below. */ - unsigned int (*receive_buf)(struct tty_struct *, - const unsigned char *cp, char *fp, int count); + void (*receive_buf)(struct tty_struct *, const unsigned char *cp, + char *fp, int count); void (*write_wakeup)(struct tty_struct *); void (*dcd_change)(struct tty_struct *, unsigned int, struct pps_event_time *); -- cgit v1.2.3