summaryrefslogtreecommitdiffstats
path: root/drivers/accessibility/speakup/genmap.c
diff options
context:
space:
mode:
authorPaulo Alcantara <pc@manguebit.org>2026-09-26 19:20:30 -0300
committerPaulo Alcantara <pc@manguebit.org>2026-09-30 14:24:12 -0300
commitdd05add7b2b6004c5fa3a1f276f56d8668f86b65 (patch)
tree23efdcaa0b8031f6ac6f57b6734d18d6c1adc6f2 /drivers/accessibility/speakup/genmap.c
downloadlinux-stable-dd05add7b2b6004c5fa3a1f276f56d8668f86b65.tar.gz
linux-stable-dd05add7b2b6004c5fa3a1f276f56d8668f86b65.zip
netfs: zero the tail of a short DIO/unbuffered readgrafted
The buffered read collector zero-fills the tail of a short read that stops below the inode's i_size (netfs_clear_unread()), so a read that races an extending write still returns the expected number of bytes. The non-buffered collector path does no such thing: it just records how much was transferred. Add the same zero-fill for the non-buffered case, gated on NETFS_SREQ_CLEAR_TAIL: a subreq's source sets that flag when a short result from it is known to be safe to treat as a hole, as opposed to NETFS_SREQ_HIT_EOF, which means the read genuinely ran off the end of the file and should be reported short as-is. Only CLEAR_TAIL should zero-fill here; a real EOF must stay a real short read. No source currently sets CLEAR_TAIL on an unbuffered/DIO subrequest, so this is inert on its own -- a following change teaches cifs to set it in the one case that needs it. Fixes: e2d46f2ec332 ("netfs: Change the read result collector to only use one work item") Reviewed-by: David Howells <dhowells@redhat.com> Reviewed-by: Namjae Jeon <linkinjeon@kernel.org> Signed-off-by: Paulo Alcantara <pc@manguebit.org> Cc: Christian Brauner <brauner@kernel.org> Cc: Matthew Wilcox <willy@infradead.org> Cc: Ronnie Sahlberg <ronniesahlberg@gmail.com> Cc: Shyam Prasad N <sprasad@microsoft.com> Cc: Tom Talpey <tom@talpey.com> Cc: Bharath SM <bharathsm@microsoft.com> Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers/accessibility/speakup/genmap.c')
-rw-r--r--drivers/accessibility/speakup/genmap.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/drivers/accessibility/speakup/genmap.c b/drivers/accessibility/speakup/genmap.c
new file mode 100644
index 000000000..a9e308bdd
--- /dev/null
+++ b/drivers/accessibility/speakup/genmap.c
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* genmap.c
+ * originally written by: Kirk Reiser.
+ *
+ ** Copyright (C) 2002 Kirk Reiser.
+ * Copyright (C) 2003 David Borowski.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <libgen.h>
+#include <string.h>
+#include <ctype.h>
+#include "utils.h"
+
+struct st_key_init {
+ char *name;
+ int value, shift;
+};
+
+static unsigned char key_data[MAXKEYVAL][16], *kp;
+
+#include "mapdata.h"
+
+static const char delims[] = "\t\n ";
+static char *cp;
+static int map_ver = 119; /* an arbitrary number so speakup can check */
+static int shift_table[17];
+static int max_states = 1, flags;
+/* flags reserved for later, maybe for individual console maps */
+
+static int get_shift_value(int state)
+{
+ int i;
+
+ for (i = 0; shift_table[i] != state; i++) {
+ if (shift_table[i] == -1) {
+ if (i >= 16)
+ oops("too many shift states", NULL);
+ shift_table[i] = state;
+ max_states = i+1;
+ break;
+ }
+ }
+ return i;
+}
+
+int
+main(int argc, char *argv[])
+{
+ int value, shift_state, i, spk_val = 0, lock_val = 0;
+ int max_key_used = 0, num_keys_used = 0;
+ struct st_key *this;
+ struct st_key_init *p_init;
+ char buffer[256];
+
+ bzero(key_table, sizeof(key_table));
+ bzero(key_data, sizeof(key_data));
+
+ shift_table[0] = 0;
+ for (i = 1; i <= 16; i++)
+ shift_table[i] = -1;
+
+ if (argc < 2) {
+ fputs("usage: genmap filename\n", stderr);
+ exit(1);
+ }
+
+ for (p_init = init_key_data; p_init->name[0] != '.'; p_init++)
+ add_key(p_init->name, p_init->value, p_init->shift);
+
+ open_input(NULL, argv[1]);
+ while (fgets(buffer, sizeof(buffer), infile)) {
+ value = shift_state = 0;
+
+ cp = strtok(buffer, delims);
+ if (*cp == '#')
+ continue;
+
+ while (cp) {
+ if (*cp == '=')
+ break;
+ this = find_key(cp);
+ if (this == NULL)
+ oops("unknown key/modifier", cp);
+ if (this->shift == is_shift) {
+ if (value)
+ oops("modifiers must come first", cp);
+ shift_state += this->value;
+ } else if (this->shift == is_input)
+ value = this->value;
+ else
+ oops("bad modifier or key", cp);
+ cp = strtok(0, delims);
+ }
+ if (!cp)
+ oops("no = found", NULL);
+
+ cp = strtok(0, delims);
+ if (!cp)
+ oops("no speakup function after =", NULL);
+
+ this = find_key(cp);
+ if (this == NULL || this->shift != is_spk)
+ oops("invalid speakup function", cp);
+
+ i = get_shift_value(shift_state);
+ if (key_data[value][i]) {
+ while (--cp > buffer)
+ if (!*cp)
+ *cp = ' ';
+ oops("two functions on same key combination", cp);
+ }
+ key_data[value][i] = (char)this->value;
+ if (value > max_key_used)
+ max_key_used = value;
+ }
+ fclose(infile);
+
+ this = find_key("spk_key");
+ if (this)
+ spk_val = this->value;
+
+ this = find_key("spk_lock");
+ if (this)
+ lock_val = this->value;
+
+ for (lc = 1; lc <= max_key_used; lc++) {
+ kp = key_data[lc];
+ if (!memcmp(key_data[0], kp, 16))
+ continue;
+ num_keys_used++;
+ for (i = 0; i < max_states; i++) {
+ if (kp[i] != spk_val && kp[i] != lock_val)
+ continue;
+ shift_state = shift_table[i];
+ if (shift_state&16)
+ continue;
+ shift_state = get_shift_value(shift_state+16);
+ kp[shift_state] = kp[i];
+ /* fill in so we can process the key up, as spk bit will be set */
+ }
+ }
+
+ printf("\t%d, %d, %d,\n\t", map_ver, num_keys_used, max_states);
+ for (i = 0; i < max_states; i++)
+ printf("%d, ", shift_table[i]);
+ printf("%d,", flags);
+ for (lc = 1; lc <= max_key_used; lc++) {
+ kp = key_data[lc];
+ if (!memcmp(key_data[0], kp, 16))
+ continue;
+ printf("\n\t%d,", lc);
+ for (i = 0; i < max_states; i++)
+ printf(" %u,", (unsigned int)kp[i]);
+ }
+ printf("\n\t0, %d\n", map_ver);
+
+ exit(0);
+}