From: Greg Kroah-Hartman Date: Wed, 12 Nov 2014 01:07:37 +0000 (+0900) Subject: 3.17-stable patches X-Git-Tag: v3.10.60~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=1ca11478f914d4cf6ceb4ad5e883820fde32e0ae;p=thirdparty%2Fkernel%2Fstable-queue.git 3.17-stable patches added patches: arm-dts-zynq-enable-pl-clocks-for-parallella.patch btrfs-fix-kfree-on-list_head-in-btrfs_lookup_csums_range-error-cleanup.patch hid-add-keyboard-input-assist-hid-usages.patch of-fix-overflow-bug-in-string-property-parsing-functions.patch xfs-bulkstat-btree-walk-doesn-t-terminate.patch xfs-bulkstat-chunk-formatter-has-issues.patch xfs-bulkstat-chunk-formatting-cursor-is-broken.patch xfs-bulkstat-doesn-t-release-agi-buffer-on-error.patch xfs-bulkstat-error-handling-is-broken.patch xfs-bulkstat-main-loop-logic-is-a-mess.patch xfs-check-error-during-inode-btree-iteration-in-xfs_bulkstat.patch xfs-track-bulkstat-progress-by-agino.patch --- diff --git a/queue-3.17/arm-dts-zynq-enable-pl-clocks-for-parallella.patch b/queue-3.17/arm-dts-zynq-enable-pl-clocks-for-parallella.patch new file mode 100644 index 00000000000..3362ee87980 --- /dev/null +++ b/queue-3.17/arm-dts-zynq-enable-pl-clocks-for-parallella.patch @@ -0,0 +1,43 @@ +From 92c9e0c780e61f821ab8a08f0d4d4fd33ba1197c Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andreas=20F=C3=A4rber?= +Date: Thu, 6 Nov 2014 18:22:10 +0100 +Subject: ARM: dts: zynq: Enable PL clocks for Parallella +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: =?UTF-8?q?Andreas=20F=C3=A4rber?= + +commit 92c9e0c780e61f821ab8a08f0d4d4fd33ba1197c upstream. + +The Parallella board comes with a U-Boot bootloader that loads one of +two predefined FPGA bitstreams before booting the kernel. Both define an +AXI interface to the on-board Epiphany processor. + +Enable clocks FCLK0..FCLK3 for the Programmable Logic by default. + +Otherwise accessing, e.g., the ESYSRESET register freezes the board, +as seen with the Epiphany SDK tools e-reset and e-hw-rev, using /dev/mem. + +Signed-off-by: Andreas Färber +Acked-by: Michal Simek +Signed-off-by: Olof Johansson +Signed-off-by: Greg Kroah-Hartman + +--- + arch/arm/boot/dts/zynq-parallella.dts | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/arch/arm/boot/dts/zynq-parallella.dts ++++ b/arch/arm/boot/dts/zynq-parallella.dts +@@ -34,6 +34,10 @@ + }; + }; + ++&clkc { ++ fclk-enable = <0xf>; ++}; ++ + &gem0 { + status = "okay"; + phy-mode = "rgmii-id"; diff --git a/queue-3.17/btrfs-fix-kfree-on-list_head-in-btrfs_lookup_csums_range-error-cleanup.patch b/queue-3.17/btrfs-fix-kfree-on-list_head-in-btrfs_lookup_csums_range-error-cleanup.patch new file mode 100644 index 00000000000..d68b1d175e9 --- /dev/null +++ b/queue-3.17/btrfs-fix-kfree-on-list_head-in-btrfs_lookup_csums_range-error-cleanup.patch @@ -0,0 +1,36 @@ +From 6e5aafb27419f32575b27ef9d6a31e5d54661aca Mon Sep 17 00:00:00 2001 +From: Chris Mason +Date: Tue, 4 Nov 2014 06:59:04 -0800 +Subject: Btrfs: fix kfree on list_head in btrfs_lookup_csums_range error cleanup + +From: Chris Mason + +commit 6e5aafb27419f32575b27ef9d6a31e5d54661aca upstream. + +If we hit any errors in btrfs_lookup_csums_range, we'll loop through all +the csums we allocate and free them. But the code was using list_entry +incorrectly, and ended up trying to free the on-stack list_head instead. + +This bug came from commit 0678b6185 + +btrfs: Don't BUG_ON kzalloc error in btrfs_lookup_csums_range() + +Signed-off-by: Chris Mason +Reported-by: Erik Berg +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/file-item.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/fs/btrfs/file-item.c ++++ b/fs/btrfs/file-item.c +@@ -423,7 +423,7 @@ int btrfs_lookup_csums_range(struct btrf + ret = 0; + fail: + while (ret < 0 && !list_empty(&tmplist)) { +- sums = list_entry(&tmplist, struct btrfs_ordered_sum, list); ++ sums = list_entry(tmplist.next, struct btrfs_ordered_sum, list); + list_del(&sums->list); + kfree(sums); + } diff --git a/queue-3.17/hid-add-keyboard-input-assist-hid-usages.patch b/queue-3.17/hid-add-keyboard-input-assist-hid-usages.patch new file mode 100644 index 00000000000..d3939dc686e --- /dev/null +++ b/queue-3.17/hid-add-keyboard-input-assist-hid-usages.patch @@ -0,0 +1,71 @@ +From f974008f07a62171a9dede08250c9a35c2b2b986 Mon Sep 17 00:00:00 2001 +From: Olivier Gay +Date: Sat, 18 Oct 2014 01:53:39 +0200 +Subject: HID: add keyboard input assist hid usages + +From: Olivier Gay + +commit f974008f07a62171a9dede08250c9a35c2b2b986 upstream. + +Add keyboard input assist controls usages from approved +hid usage table request HUTTR42: +http://www.usb.org/developers/hidpage/HUTRR42c.pdf + +Signed-off-by: Olivier Gay +Acked-by: Dmitry Torokhov +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/hid/hid-debug.c | 6 ++++++ + drivers/hid/hid-input.c | 7 +++++++ + include/uapi/linux/input.h | 7 +++++++ + 3 files changed, 20 insertions(+) + +--- a/drivers/hid/hid-debug.c ++++ b/drivers/hid/hid-debug.c +@@ -946,6 +946,12 @@ static const char *keys[KEY_MAX + 1] = { + [KEY_BRIGHTNESS_MIN] = "BrightnessMin", + [KEY_BRIGHTNESS_MAX] = "BrightnessMax", + [KEY_BRIGHTNESS_AUTO] = "BrightnessAuto", ++ [KEY_KBDINPUTASSIST_PREV] = "KbdInputAssistPrev", ++ [KEY_KBDINPUTASSIST_NEXT] = "KbdInputAssistNext", ++ [KEY_KBDINPUTASSIST_PREVGROUP] = "KbdInputAssistPrevGroup", ++ [KEY_KBDINPUTASSIST_NEXTGROUP] = "KbdInputAssistNextGroup", ++ [KEY_KBDINPUTASSIST_ACCEPT] = "KbdInputAssistAccept", ++ [KEY_KBDINPUTASSIST_CANCEL] = "KbdInputAssistCancel", + }; + + static const char *relatives[REL_MAX + 1] = { +--- a/drivers/hid/hid-input.c ++++ b/drivers/hid/hid-input.c +@@ -859,6 +859,13 @@ static void hidinput_configure_usage(str + case 0x28b: map_key_clear(KEY_FORWARDMAIL); break; + case 0x28c: map_key_clear(KEY_SEND); break; + ++ case 0x2c7: map_key_clear(KEY_KBDINPUTASSIST_PREV); break; ++ case 0x2c8: map_key_clear(KEY_KBDINPUTASSIST_NEXT); break; ++ case 0x2c9: map_key_clear(KEY_KBDINPUTASSIST_PREVGROUP); break; ++ case 0x2ca: map_key_clear(KEY_KBDINPUTASSIST_NEXTGROUP); break; ++ case 0x2cb: map_key_clear(KEY_KBDINPUTASSIST_ACCEPT); break; ++ case 0x2cc: map_key_clear(KEY_KBDINPUTASSIST_CANCEL); break; ++ + default: goto ignore; + } + break; +--- a/include/uapi/linux/input.h ++++ b/include/uapi/linux/input.h +@@ -739,6 +739,13 @@ struct input_keymap_entry { + #define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ + #define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ + ++#define KEY_KBDINPUTASSIST_PREV 0x260 ++#define KEY_KBDINPUTASSIST_NEXT 0x261 ++#define KEY_KBDINPUTASSIST_PREVGROUP 0x262 ++#define KEY_KBDINPUTASSIST_NEXTGROUP 0x263 ++#define KEY_KBDINPUTASSIST_ACCEPT 0x264 ++#define KEY_KBDINPUTASSIST_CANCEL 0x265 ++ + #define BTN_TRIGGER_HAPPY 0x2c0 + #define BTN_TRIGGER_HAPPY1 0x2c0 + #define BTN_TRIGGER_HAPPY2 0x2c1 diff --git a/queue-3.17/of-fix-overflow-bug-in-string-property-parsing-functions.patch b/queue-3.17/of-fix-overflow-bug-in-string-property-parsing-functions.patch new file mode 100644 index 00000000000..edb1eff40dc --- /dev/null +++ b/queue-3.17/of-fix-overflow-bug-in-string-property-parsing-functions.patch @@ -0,0 +1,382 @@ +From a87fa1d81a9fb5e9adca9820e16008c40ad09f33 Mon Sep 17 00:00:00 2001 +From: Grant Likely +Date: Mon, 3 Nov 2014 15:15:35 +0000 +Subject: of: Fix overflow bug in string property parsing functions + +From: Grant Likely + +commit a87fa1d81a9fb5e9adca9820e16008c40ad09f33 upstream. + +The string property read helpers will run off the end of the buffer if +it is handed a malformed string property. Rework the parsers to make +sure that doesn't happen. At the same time add new test cases to make +sure the functions behave themselves. + +The original implementations of of_property_read_string_index() and +of_property_count_strings() both open-coded the same block of parsing +code, each with it's own subtly different bugs. The fix here merges +functions into a single helper and makes the original functions static +inline wrappers around the helper. + +One non-bugfix aspect of this patch is the addition of a new wrapper, +of_property_read_string_array(). The new wrapper is needed by the +device_properties feature that Rafael is working on and planning to +merge for v3.19. The implementation is identical both with and without +the new static inline wrapper, so it just got left in to reduce the +churn on the header file. + +Signed-off-by: Grant Likely +Cc: Rafael J. Wysocki +Cc: Mika Westerberg +Cc: Rob Herring +Cc: Arnd Bergmann +Cc: Darren Hart +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/of/base.c | 88 +++++++--------------------- + drivers/of/selftest.c | 66 +++++++++++++++++++-- + drivers/of/testcase-data/tests-phandle.dtsi | 2 + include/linux/of.h | 84 ++++++++++++++++++++++---- + 4 files changed, 154 insertions(+), 86 deletions(-) + +--- a/drivers/of/base.c ++++ b/drivers/of/base.c +@@ -1277,52 +1277,6 @@ int of_property_read_string(struct devic + EXPORT_SYMBOL_GPL(of_property_read_string); + + /** +- * of_property_read_string_index - Find and read a string from a multiple +- * strings property. +- * @np: device node from which the property value is to be read. +- * @propname: name of the property to be searched. +- * @index: index of the string in the list of strings +- * @out_string: pointer to null terminated return string, modified only if +- * return value is 0. +- * +- * Search for a property in a device tree node and retrieve a null +- * terminated string value (pointer to data, not a copy) in the list of strings +- * contained in that property. +- * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if +- * property does not have a value, and -EILSEQ if the string is not +- * null-terminated within the length of the property data. +- * +- * The out_string pointer is modified only if a valid string can be decoded. +- */ +-int of_property_read_string_index(struct device_node *np, const char *propname, +- int index, const char **output) +-{ +- struct property *prop = of_find_property(np, propname, NULL); +- int i = 0; +- size_t l = 0, total = 0; +- const char *p; +- +- if (!prop) +- return -EINVAL; +- if (!prop->value) +- return -ENODATA; +- if (strnlen(prop->value, prop->length) >= prop->length) +- return -EILSEQ; +- +- p = prop->value; +- +- for (i = 0; total < prop->length; total += l, p += l) { +- l = strlen(p) + 1; +- if (i++ == index) { +- *output = p; +- return 0; +- } +- } +- return -ENODATA; +-} +-EXPORT_SYMBOL_GPL(of_property_read_string_index); +- +-/** + * of_property_match_string() - Find string in a list and return index + * @np: pointer to node containing string list property + * @propname: string list property name +@@ -1348,7 +1302,7 @@ int of_property_match_string(struct devi + end = p + prop->length; + + for (i = 0; p < end; i++, p += l) { +- l = strlen(p) + 1; ++ l = strnlen(p, end - p) + 1; + if (p + l > end) + return -EILSEQ; + pr_debug("comparing %s with %s\n", string, p); +@@ -1360,39 +1314,41 @@ int of_property_match_string(struct devi + EXPORT_SYMBOL_GPL(of_property_match_string); + + /** +- * of_property_count_strings - Find and return the number of strings from a +- * multiple strings property. ++ * of_property_read_string_util() - Utility helper for parsing string properties + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. ++ * @out_strs: output array of string pointers. ++ * @sz: number of array elements to read. ++ * @skip: Number of strings to skip over at beginning of list. + * +- * Search for a property in a device tree node and retrieve the number of null +- * terminated string contain in it. Returns the number of strings on +- * success, -EINVAL if the property does not exist, -ENODATA if property +- * does not have a value, and -EILSEQ if the string is not null-terminated +- * within the length of the property data. ++ * Don't call this function directly. It is a utility helper for the ++ * of_property_read_string*() family of functions. + */ +-int of_property_count_strings(struct device_node *np, const char *propname) ++int of_property_read_string_helper(struct device_node *np, const char *propname, ++ const char **out_strs, size_t sz, int skip) + { + struct property *prop = of_find_property(np, propname, NULL); +- int i = 0; +- size_t l = 0, total = 0; +- const char *p; ++ int l = 0, i = 0; ++ const char *p, *end; + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; +- if (strnlen(prop->value, prop->length) >= prop->length) +- return -EILSEQ; +- + p = prop->value; ++ end = p + prop->length; + +- for (i = 0; total < prop->length; total += l, p += l, i++) +- l = strlen(p) + 1; +- +- return i; ++ for (i = 0; p < end && (!out_strs || i < skip + sz); i++, p += l) { ++ l = strnlen(p, end - p) + 1; ++ if (p + l > end) ++ return -EILSEQ; ++ if (out_strs && i >= skip) ++ *out_strs++ = p; ++ } ++ i -= skip; ++ return i <= 0 ? -ENODATA : i; + } +-EXPORT_SYMBOL_GPL(of_property_count_strings); ++EXPORT_SYMBOL_GPL(of_property_read_string_helper); + + void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) + { +--- a/drivers/of/selftest.c ++++ b/drivers/of/selftest.c +@@ -247,8 +247,9 @@ static void __init of_selftest_parse_pha + selftest(rc == -EINVAL, "expected:%i got:%i\n", -EINVAL, rc); + } + +-static void __init of_selftest_property_match_string(void) ++static void __init of_selftest_property_string(void) + { ++ const char *strings[4]; + struct device_node *np; + int rc; + +@@ -265,13 +266,66 @@ static void __init of_selftest_property_ + rc = of_property_match_string(np, "phandle-list-names", "third"); + selftest(rc == 2, "third expected:0 got:%i\n", rc); + rc = of_property_match_string(np, "phandle-list-names", "fourth"); +- selftest(rc == -ENODATA, "unmatched string; rc=%i", rc); ++ selftest(rc == -ENODATA, "unmatched string; rc=%i\n", rc); + rc = of_property_match_string(np, "missing-property", "blah"); +- selftest(rc == -EINVAL, "missing property; rc=%i", rc); ++ selftest(rc == -EINVAL, "missing property; rc=%i\n", rc); + rc = of_property_match_string(np, "empty-property", "blah"); +- selftest(rc == -ENODATA, "empty property; rc=%i", rc); ++ selftest(rc == -ENODATA, "empty property; rc=%i\n", rc); + rc = of_property_match_string(np, "unterminated-string", "blah"); +- selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc); ++ selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); ++ ++ /* of_property_count_strings() tests */ ++ rc = of_property_count_strings(np, "string-property"); ++ selftest(rc == 1, "Incorrect string count; rc=%i\n", rc); ++ rc = of_property_count_strings(np, "phandle-list-names"); ++ selftest(rc == 3, "Incorrect string count; rc=%i\n", rc); ++ rc = of_property_count_strings(np, "unterminated-string"); ++ selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); ++ rc = of_property_count_strings(np, "unterminated-string-list"); ++ selftest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc); ++ ++ /* of_property_read_string_index() tests */ ++ rc = of_property_read_string_index(np, "string-property", 0, strings); ++ selftest(rc == 0 && !strcmp(strings[0], "foobar"), "of_property_read_string_index() failure; rc=%i\n", rc); ++ strings[0] = NULL; ++ rc = of_property_read_string_index(np, "string-property", 1, strings); ++ selftest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); ++ rc = of_property_read_string_index(np, "phandle-list-names", 0, strings); ++ selftest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc); ++ rc = of_property_read_string_index(np, "phandle-list-names", 1, strings); ++ selftest(rc == 0 && !strcmp(strings[0], "second"), "of_property_read_string_index() failure; rc=%i\n", rc); ++ rc = of_property_read_string_index(np, "phandle-list-names", 2, strings); ++ selftest(rc == 0 && !strcmp(strings[0], "third"), "of_property_read_string_index() failure; rc=%i\n", rc); ++ strings[0] = NULL; ++ rc = of_property_read_string_index(np, "phandle-list-names", 3, strings); ++ selftest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); ++ strings[0] = NULL; ++ rc = of_property_read_string_index(np, "unterminated-string", 0, strings); ++ selftest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); ++ rc = of_property_read_string_index(np, "unterminated-string-list", 0, strings); ++ selftest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc); ++ strings[0] = NULL; ++ rc = of_property_read_string_index(np, "unterminated-string-list", 2, strings); /* should fail */ ++ selftest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc); ++ strings[1] = NULL; ++ ++ /* of_property_read_string_array() tests */ ++ rc = of_property_read_string_array(np, "string-property", strings, 4); ++ selftest(rc == 1, "Incorrect string count; rc=%i\n", rc); ++ rc = of_property_read_string_array(np, "phandle-list-names", strings, 4); ++ selftest(rc == 3, "Incorrect string count; rc=%i\n", rc); ++ rc = of_property_read_string_array(np, "unterminated-string", strings, 4); ++ selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc); ++ /* -- An incorrectly formed string should cause a failure */ ++ rc = of_property_read_string_array(np, "unterminated-string-list", strings, 4); ++ selftest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc); ++ /* -- parsing the correctly formed strings should still work: */ ++ strings[2] = NULL; ++ rc = of_property_read_string_array(np, "unterminated-string-list", strings, 2); ++ selftest(rc == 2 && strings[2] == NULL, "of_property_read_string_array() failure; rc=%i\n", rc); ++ strings[1] = NULL; ++ rc = of_property_read_string_array(np, "phandle-list-names", strings, 1); ++ selftest(rc == 1 && strings[1] == NULL, "Overwrote end of string array; rc=%i, str='%s'\n", rc, strings[1]); + } + + #define propcmp(p1, p2) (((p1)->length == (p2)->length) && \ +@@ -783,7 +837,7 @@ static int __init of_selftest(void) + of_selftest_find_node_by_name(); + of_selftest_dynamic(); + of_selftest_parse_phandle_with_args(); +- of_selftest_property_match_string(); ++ of_selftest_property_string(); + of_selftest_property_copy(); + of_selftest_changeset(); + of_selftest_parse_interrupts(); +--- a/drivers/of/testcase-data/tests-phandle.dtsi ++++ b/drivers/of/testcase-data/tests-phandle.dtsi +@@ -39,7 +39,9 @@ + phandle-list-bad-args = <&provider2 1 0>, + <&provider3 0>; + empty-property; ++ string-property = "foobar"; + unterminated-string = [40 41 42 43]; ++ unterminated-string-list = "first", "second", [40 41 42 43]; + }; + }; + }; +--- a/include/linux/of.h ++++ b/include/linux/of.h +@@ -267,14 +267,12 @@ extern int of_property_read_u64(const st + extern int of_property_read_string(struct device_node *np, + const char *propname, + const char **out_string); +-extern int of_property_read_string_index(struct device_node *np, +- const char *propname, +- int index, const char **output); + extern int of_property_match_string(struct device_node *np, + const char *propname, + const char *string); +-extern int of_property_count_strings(struct device_node *np, +- const char *propname); ++extern int of_property_read_string_helper(struct device_node *np, ++ const char *propname, ++ const char **out_strs, size_t sz, int index); + extern int of_device_is_compatible(const struct device_node *device, + const char *); + extern int of_device_is_available(const struct device_node *device); +@@ -486,15 +484,9 @@ static inline int of_property_read_strin + return -ENOSYS; + } + +-static inline int of_property_read_string_index(struct device_node *np, +- const char *propname, int index, +- const char **out_string) +-{ +- return -ENOSYS; +-} +- +-static inline int of_property_count_strings(struct device_node *np, +- const char *propname) ++static inline int of_property_read_string_helper(struct device_node *np, ++ const char *propname, ++ const char **out_strs, size_t sz, int index) + { + return -ENOSYS; + } +@@ -668,6 +660,70 @@ static inline int of_property_count_u64_ + } + + /** ++ * of_property_read_string_array() - Read an array of strings from a multiple ++ * strings property. ++ * @np: device node from which the property value is to be read. ++ * @propname: name of the property to be searched. ++ * @out_strs: output array of string pointers. ++ * @sz: number of array elements to read. ++ * ++ * Search for a property in a device tree node and retrieve a list of ++ * terminated string values (pointer to data, not a copy) in that property. ++ * ++ * If @out_strs is NULL, the number of strings in the property is returned. ++ */ ++static inline int of_property_read_string_array(struct device_node *np, ++ const char *propname, const char **out_strs, ++ size_t sz) ++{ ++ return of_property_read_string_helper(np, propname, out_strs, sz, 0); ++} ++ ++/** ++ * of_property_count_strings() - Find and return the number of strings from a ++ * multiple strings property. ++ * @np: device node from which the property value is to be read. ++ * @propname: name of the property to be searched. ++ * ++ * Search for a property in a device tree node and retrieve the number of null ++ * terminated string contain in it. Returns the number of strings on ++ * success, -EINVAL if the property does not exist, -ENODATA if property ++ * does not have a value, and -EILSEQ if the string is not null-terminated ++ * within the length of the property data. ++ */ ++static inline int of_property_count_strings(struct device_node *np, ++ const char *propname) ++{ ++ return of_property_read_string_helper(np, propname, NULL, 0, 0); ++} ++ ++/** ++ * of_property_read_string_index() - Find and read a string from a multiple ++ * strings property. ++ * @np: device node from which the property value is to be read. ++ * @propname: name of the property to be searched. ++ * @index: index of the string in the list of strings ++ * @out_string: pointer to null terminated return string, modified only if ++ * return value is 0. ++ * ++ * Search for a property in a device tree node and retrieve a null ++ * terminated string value (pointer to data, not a copy) in the list of strings ++ * contained in that property. ++ * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if ++ * property does not have a value, and -EILSEQ if the string is not ++ * null-terminated within the length of the property data. ++ * ++ * The out_string pointer is modified only if a valid string can be decoded. ++ */ ++static inline int of_property_read_string_index(struct device_node *np, ++ const char *propname, ++ int index, const char **output) ++{ ++ int rc = of_property_read_string_helper(np, propname, output, 1, index); ++ return rc < 0 ? rc : 0; ++} ++ ++/** + * of_property_read_bool - Findfrom a property + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. diff --git a/queue-3.17/series b/queue-3.17/series index ea499b6fba5..6d710de1fb3 100644 --- a/queue-3.17/series +++ b/queue-3.17/series @@ -305,3 +305,15 @@ irqchip-armada-370-xp-fix-msi-interrupt-handling.patch irqchip-armada-370-xp-fix-mpic-interrupt-handling.patch i2c-at91-don-t-account-as-iowait.patch sysfs-driver-core-fix-glue-dir-race-condition-by-gdp_mutex.patch +arm-dts-zynq-enable-pl-clocks-for-parallella.patch +of-fix-overflow-bug-in-string-property-parsing-functions.patch +btrfs-fix-kfree-on-list_head-in-btrfs_lookup_csums_range-error-cleanup.patch +xfs-bulkstat-doesn-t-release-agi-buffer-on-error.patch +xfs-check-error-during-inode-btree-iteration-in-xfs_bulkstat.patch +xfs-bulkstat-btree-walk-doesn-t-terminate.patch +xfs-bulkstat-chunk-formatting-cursor-is-broken.patch +xfs-bulkstat-chunk-formatter-has-issues.patch +xfs-bulkstat-main-loop-logic-is-a-mess.patch +xfs-bulkstat-error-handling-is-broken.patch +xfs-track-bulkstat-progress-by-agino.patch +hid-add-keyboard-input-assist-hid-usages.patch diff --git a/queue-3.17/xfs-bulkstat-btree-walk-doesn-t-terminate.patch b/queue-3.17/xfs-bulkstat-btree-walk-doesn-t-terminate.patch new file mode 100644 index 00000000000..a1b274be2e8 --- /dev/null +++ b/queue-3.17/xfs-bulkstat-btree-walk-doesn-t-terminate.patch @@ -0,0 +1,93 @@ +From afa947cb52a8e73fe71915a0b0af6fcf98dfbe1a Mon Sep 17 00:00:00 2001 +From: Dave Chinner +Date: Fri, 7 Nov 2014 08:29:57 +1100 +Subject: xfs: bulkstat btree walk doesn't terminate + +From: Dave Chinner + +commit afa947cb52a8e73fe71915a0b0af6fcf98dfbe1a upstream. + +The bulkstat code has several different ways of detecting the end of +an AG when doing a walk. They are not consistently detected, and the +code that checks for the end of AG conditions is not consistently +coded. Hence the are conditions where the walk code can get stuck in +an endless loop making no progress and not triggering any +termination conditions. + +Convert all the "tmp/i" status return codes from btree operations +to a common name (stat) and apply end-of-ag detection to these +operations consistently. + +Signed-off-by: Dave Chinner +Reviewed-by: Brian Foster +Signed-off-by: Dave Chinner +Signed-off-by: Greg Kroah-Hartman + +--- + fs/xfs/xfs_itable.c | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +--- a/fs/xfs/xfs_itable.c ++++ b/fs/xfs/xfs_itable.c +@@ -356,7 +356,6 @@ xfs_bulkstat( + int end_of_ag; /* set if we've seen the ag end */ + int error; /* error code */ + int fmterror;/* bulkstat formatter result */ +- int i; /* loop index */ + int icount; /* count of inodes good in irbuf */ + size_t irbsize; /* size of irec buffer in bytes */ + xfs_ino_t ino; /* inode number (filesystem) */ +@@ -366,11 +365,11 @@ xfs_bulkstat( + xfs_ino_t lastino; /* last inode number returned */ + int nirbuf; /* size of irbuf */ + int rval; /* return value error code */ +- int tmp; /* result value from btree calls */ + int ubcount; /* size of user's buffer */ + int ubleft; /* bytes left in user's buffer */ + char __user *ubufp; /* pointer into user's buffer */ + int ubelem; /* spaces used in user's buffer */ ++ int stat; + + /* + * Get the last inode value, see if there's nothing to do. +@@ -436,13 +435,15 @@ xfs_bulkstat( + agino = r.ir_startino + XFS_INODES_PER_CHUNK; + } + /* Increment to the next record */ +- error = xfs_btree_increment(cur, 0, &tmp); ++ error = xfs_btree_increment(cur, 0, &stat); + } else { + /* Start of ag. Lookup the first inode chunk */ +- error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &tmp); ++ error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &stat); + } +- if (error) ++ if (error || stat == 0) { ++ end_of_ag = 1; + goto del_cursor; ++ } + + /* + * Loop through inode btree records in this ag, +@@ -451,8 +452,8 @@ xfs_bulkstat( + while (irbp < irbufend && icount < ubcount) { + struct xfs_inobt_rec_incore r; + +- error = xfs_inobt_get_rec(cur, &r, &i); +- if (error || i == 0) { ++ error = xfs_inobt_get_rec(cur, &r, &stat); ++ if (error || stat == 0) { + end_of_ag = 1; + goto del_cursor; + } +@@ -473,8 +474,8 @@ xfs_bulkstat( + * Set agino to after this chunk and bump the cursor. + */ + agino = r.ir_startino + XFS_INODES_PER_CHUNK; +- error = xfs_btree_increment(cur, 0, &tmp); +- if (error) { ++ error = xfs_btree_increment(cur, 0, &stat); ++ if (error || stat == 0) { + end_of_ag = 1; + goto del_cursor; + } diff --git a/queue-3.17/xfs-bulkstat-chunk-formatter-has-issues.patch b/queue-3.17/xfs-bulkstat-chunk-formatter-has-issues.patch new file mode 100644 index 00000000000..3cc83ea6403 --- /dev/null +++ b/queue-3.17/xfs-bulkstat-chunk-formatter-has-issues.patch @@ -0,0 +1,120 @@ +From 2b831ac6bc87d3cbcbb1a8816827b6923403e461 Mon Sep 17 00:00:00 2001 +From: Dave Chinner +Date: Fri, 7 Nov 2014 08:30:58 +1100 +Subject: xfs: bulkstat chunk-formatter has issues + +From: Dave Chinner + +commit 2b831ac6bc87d3cbcbb1a8816827b6923403e461 upstream. + +The loop construct has issues: + - clustidx is completely unused, so remove it. + - the loop tries to be smart by terminating when the + "freecount" tells it that all inodes are free. Just drop + it as in most cases we have to scan all inodes in the + chunk anyway. + - move the "user buffer left" condition check to the only + point where we consume space int eh user buffer. + - move the initialisation of agino out of the loop, leaving + just a simple loop control logic using the clusteridx. + +Also, double handling of the user buffer variables leads to problems +tracking the current state - use the cursor variables directly +rather than keeping local copies and then having to update the +cursor before returning. + +Signed-off-by: Dave Chinner +Reviewed-by: Brian Foster +Signed-off-by: Dave Chinner +Signed-off-by: Greg Kroah-Hartman + +--- + fs/xfs/xfs_itable.c | 58 +++++++++++++++++++++------------------------------- + 1 file changed, 24 insertions(+), 34 deletions(-) + +--- a/fs/xfs/xfs_itable.c ++++ b/fs/xfs/xfs_itable.c +@@ -283,59 +283,49 @@ xfs_bulkstat_ag_ichunk( + xfs_ino_t *lastino) + { + char __user **ubufp = acp->ac_ubuffer; +- int ubleft = acp->ac_ubleft; +- int ubelem = acp->ac_ubelem; +- int chunkidx, clustidx; ++ int chunkidx; + int error = 0; + xfs_agino_t agino; + +- for (agino = irbp->ir_startino, chunkidx = clustidx = 0; +- XFS_BULKSTAT_UBLEFT(ubleft) && +- irbp->ir_freecount < XFS_INODES_PER_CHUNK; +- chunkidx++, clustidx++, agino++) { +- int fmterror; /* bulkstat formatter result */ ++ agino = irbp->ir_startino; ++ for (chunkidx = 0; chunkidx < XFS_INODES_PER_CHUNK; ++ chunkidx++, agino++) { ++ int fmterror; + int ubused; + xfs_ino_t ino = XFS_AGINO_TO_INO(mp, agno, agino); + +- ASSERT(chunkidx < XFS_INODES_PER_CHUNK); +- + /* Skip if this inode is free */ + if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free) { + *lastino = ino; + continue; + } + +- /* +- * Count used inodes as free so we can tell when the +- * chunk is used up. +- */ +- irbp->ir_freecount++; +- + /* Get the inode and fill in a single buffer */ + ubused = statstruct_size; +- error = formatter(mp, ino, *ubufp, ubleft, &ubused, &fmterror); +- if (fmterror == BULKSTAT_RV_NOTHING) { +- if (error && error != -ENOENT && error != -EINVAL) { +- ubleft = 0; +- break; +- } +- *lastino = ino; +- continue; +- } +- if (fmterror == BULKSTAT_RV_GIVEUP) { +- ubleft = 0; ++ error = formatter(mp, ino, *ubufp, acp->ac_ubleft, ++ &ubused, &fmterror); ++ if (fmterror == BULKSTAT_RV_GIVEUP || ++ (error && error != -ENOENT && error != -EINVAL)) { ++ acp->ac_ubleft = 0; + ASSERT(error); + break; + } +- if (*ubufp) +- *ubufp += ubused; +- ubleft -= ubused; +- ubelem++; ++ ++ /* be careful not to leak error if at end of chunk */ ++ if (fmterror == BULKSTAT_RV_NOTHING || error) { ++ *lastino = ino; ++ error = 0; ++ continue; ++ } ++ ++ *ubufp += ubused; ++ acp->ac_ubleft -= ubused; ++ acp->ac_ubelem++; + *lastino = ino; +- } + +- acp->ac_ubleft = ubleft; +- acp->ac_ubelem = ubelem; ++ if (acp->ac_ubleft < statstruct_size) ++ break; ++ } + + return error; + } diff --git a/queue-3.17/xfs-bulkstat-chunk-formatting-cursor-is-broken.patch b/queue-3.17/xfs-bulkstat-chunk-formatting-cursor-is-broken.patch new file mode 100644 index 00000000000..2fbe046f677 --- /dev/null +++ b/queue-3.17/xfs-bulkstat-chunk-formatting-cursor-is-broken.patch @@ -0,0 +1,223 @@ +From bf4a5af20d25ecc8876978ad34b8db83b4235f3c Mon Sep 17 00:00:00 2001 +From: Dave Chinner +Date: Fri, 7 Nov 2014 08:30:30 +1100 +Subject: xfs: bulkstat chunk formatting cursor is broken + +From: Dave Chinner + +commit bf4a5af20d25ecc8876978ad34b8db83b4235f3c upstream. + +The xfs_bulkstat_agichunk formatting cursor takes buffer values from +the main loop and passes them via the structure to the chunk +formatter, and the writes the changed values back into the main loop +local variables. Unfortunately, this complex dance is full of corner +cases that aren't handled correctly. + +The biggest problem is that it is double handling the information in +both the main loop and the chunk formatting function, leading to +inconsistent updates and endless loops where progress is not made. + +To fix this, push the struct xfs_bulkstat_agichunk outwards to be +the primary holder of user buffer information. this removes the +double handling in the main loop. + +Also, pass the last inode processed by the chunk formatter as a +separate parameter as it purely an output variable and is not +related to the user buffer consumption cursor. + +Finally, the chunk formatting code is not shared by anyone, so make +it local to xfs_itable.c. + +Signed-off-by: Dave Chinner +Reviewed-by: Brian Foster +Signed-off-by: Dave Chinner +Signed-off-by: Greg Kroah-Hartman + +--- + fs/xfs/xfs_itable.c | 59 ++++++++++++++++++++++++---------------------------- + fs/xfs/xfs_itable.h | 16 -------------- + 2 files changed, 28 insertions(+), 47 deletions(-) + +--- a/fs/xfs/xfs_itable.c ++++ b/fs/xfs/xfs_itable.c +@@ -262,20 +262,26 @@ xfs_bulkstat_grab_ichunk( + + #define XFS_BULKSTAT_UBLEFT(ubleft) ((ubleft) >= statstruct_size) + ++struct xfs_bulkstat_agichunk { ++ char __user **ac_ubuffer;/* pointer into user's buffer */ ++ int ac_ubleft; /* bytes left in user's buffer */ ++ int ac_ubelem; /* spaces used in user's buffer */ ++}; ++ + /* + * Process inodes in chunk with a pointer to a formatter function + * that will iget the inode and fill in the appropriate structure. + */ +-int ++static int + xfs_bulkstat_ag_ichunk( + struct xfs_mount *mp, + xfs_agnumber_t agno, + struct xfs_inobt_rec_incore *irbp, + bulkstat_one_pf formatter, + size_t statstruct_size, +- struct xfs_bulkstat_agichunk *acp) ++ struct xfs_bulkstat_agichunk *acp, ++ xfs_ino_t *lastino) + { +- xfs_ino_t lastino = acp->ac_lastino; + char __user **ubufp = acp->ac_ubuffer; + int ubleft = acp->ac_ubleft; + int ubelem = acp->ac_ubelem; +@@ -295,7 +301,7 @@ xfs_bulkstat_ag_ichunk( + + /* Skip if this inode is free */ + if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free) { +- lastino = ino; ++ *lastino = ino; + continue; + } + +@@ -313,7 +319,7 @@ xfs_bulkstat_ag_ichunk( + ubleft = 0; + break; + } +- lastino = ino; ++ *lastino = ino; + continue; + } + if (fmterror == BULKSTAT_RV_GIVEUP) { +@@ -325,10 +331,9 @@ xfs_bulkstat_ag_ichunk( + *ubufp += ubused; + ubleft -= ubused; + ubelem++; +- lastino = ino; ++ *lastino = ino; + } + +- acp->ac_lastino = lastino; + acp->ac_ubleft = ubleft; + acp->ac_ubelem = ubelem; + +@@ -355,7 +360,6 @@ xfs_bulkstat( + xfs_btree_cur_t *cur; /* btree cursor for ialloc btree */ + int end_of_ag; /* set if we've seen the ag end */ + int error; /* error code */ +- int fmterror;/* bulkstat formatter result */ + int icount; /* count of inodes good in irbuf */ + size_t irbsize; /* size of irec buffer in bytes */ + xfs_ino_t ino; /* inode number (filesystem) */ +@@ -366,10 +370,8 @@ xfs_bulkstat( + int nirbuf; /* size of irbuf */ + int rval; /* return value error code */ + int ubcount; /* size of user's buffer */ +- int ubleft; /* bytes left in user's buffer */ +- char __user *ubufp; /* pointer into user's buffer */ +- int ubelem; /* spaces used in user's buffer */ + int stat; ++ struct xfs_bulkstat_agichunk ac; + + /* + * Get the last inode value, see if there's nothing to do. +@@ -386,11 +388,13 @@ xfs_bulkstat( + } + + ubcount = *ubcountp; /* statstruct's */ +- ubleft = ubcount * statstruct_size; /* bytes */ +- *ubcountp = ubelem = 0; ++ ac.ac_ubuffer = &ubuffer; ++ ac.ac_ubleft = ubcount * statstruct_size; /* bytes */; ++ ac.ac_ubelem = 0; ++ ++ *ubcountp = 0; + *done = 0; +- fmterror = 0; +- ubufp = ubuffer; ++ + irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 4); + if (!irbuf) + return -ENOMEM; +@@ -402,7 +406,7 @@ xfs_bulkstat( + * inode returned; 0 means start of the allocation group. + */ + rval = 0; +- while (XFS_BULKSTAT_UBLEFT(ubleft) && agno < mp->m_sb.sb_agcount) { ++ while (XFS_BULKSTAT_UBLEFT(ac.ac_ubleft) && agno < mp->m_sb.sb_agcount) { + cond_resched(); + error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); + if (error) +@@ -497,28 +501,21 @@ del_cursor: + */ + irbufend = irbp; + for (irbp = irbuf; +- irbp < irbufend && XFS_BULKSTAT_UBLEFT(ubleft); irbp++) { +- struct xfs_bulkstat_agichunk ac; +- +- ac.ac_lastino = lastino; +- ac.ac_ubuffer = &ubuffer; +- ac.ac_ubleft = ubleft; +- ac.ac_ubelem = ubelem; ++ irbp < irbufend && XFS_BULKSTAT_UBLEFT(ac.ac_ubleft); ++ irbp++) { + error = xfs_bulkstat_ag_ichunk(mp, agno, irbp, +- formatter, statstruct_size, &ac); ++ formatter, statstruct_size, &ac, ++ &lastino); + if (error) + rval = error; + +- lastino = ac.ac_lastino; +- ubleft = ac.ac_ubleft; +- ubelem = ac.ac_ubelem; +- + cond_resched(); + } ++ + /* + * Set up for the next loop iteration. + */ +- if (XFS_BULKSTAT_UBLEFT(ubleft)) { ++ if (XFS_BULKSTAT_UBLEFT(ac.ac_ubleft)) { + if (end_of_ag) { + agno++; + agino = 0; +@@ -531,11 +528,11 @@ del_cursor: + * Done, we're either out of filesystem or space to put the data. + */ + kmem_free(irbuf); +- *ubcountp = ubelem; ++ *ubcountp = ac.ac_ubelem; + /* + * Found some inodes, return them now and return the error next time. + */ +- if (ubelem) ++ if (ac.ac_ubelem) + rval = 0; + if (agno >= mp->m_sb.sb_agcount) { + /* +--- a/fs/xfs/xfs_itable.h ++++ b/fs/xfs/xfs_itable.h +@@ -30,22 +30,6 @@ typedef int (*bulkstat_one_pf)(struct xf + int *ubused, + int *stat); + +-struct xfs_bulkstat_agichunk { +- xfs_ino_t ac_lastino; /* last inode returned */ +- char __user **ac_ubuffer;/* pointer into user's buffer */ +- int ac_ubleft; /* bytes left in user's buffer */ +- int ac_ubelem; /* spaces used in user's buffer */ +-}; +- +-int +-xfs_bulkstat_ag_ichunk( +- struct xfs_mount *mp, +- xfs_agnumber_t agno, +- struct xfs_inobt_rec_incore *irbp, +- bulkstat_one_pf formatter, +- size_t statstruct_size, +- struct xfs_bulkstat_agichunk *acp); +- + /* + * Values for stat return value. + */ diff --git a/queue-3.17/xfs-bulkstat-doesn-t-release-agi-buffer-on-error.patch b/queue-3.17/xfs-bulkstat-doesn-t-release-agi-buffer-on-error.patch new file mode 100644 index 00000000000..51ccc803b2c --- /dev/null +++ b/queue-3.17/xfs-bulkstat-doesn-t-release-agi-buffer-on-error.patch @@ -0,0 +1,75 @@ +From a6bbce54efa9145dbcf3029c885549f7ebc40a3b Mon Sep 17 00:00:00 2001 +From: Dave Chinner +Date: Wed, 29 Oct 2014 08:22:18 +1100 +Subject: xfs: bulkstat doesn't release AGI buffer on error + +From: Dave Chinner + +commit a6bbce54efa9145dbcf3029c885549f7ebc40a3b upstream. + +The recent refactoring of the bulkstat code left a small landmine in +the code. If a inobt read fails, then the tree walk is aborted and +returns without releasing the AGI buffer or freeing the cursor. This +can lead to a subsequent bulkstat call hanging trying to grab the +AGI buffer again. + +Signed-off-by: Dave Chinner +Reviewed-by: Brian Foster +Reviewed-by: Eric Sandeen +Signed-off-by: Dave Chinner +Signed-off-by: Greg Kroah-Hartman + +--- + fs/xfs/xfs_itable.c | 16 ++++++++++------ + 1 file changed, 10 insertions(+), 6 deletions(-) + +--- a/fs/xfs/xfs_itable.c ++++ b/fs/xfs/xfs_itable.c +@@ -427,7 +427,7 @@ xfs_bulkstat( + + error = xfs_bulkstat_grab_ichunk(cur, agino, &icount, &r); + if (error) +- break; ++ goto del_cursor; + if (icount) { + irbp->ir_startino = r.ir_startino; + irbp->ir_freecount = r.ir_freecount; +@@ -442,7 +442,7 @@ xfs_bulkstat( + error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &tmp); + } + if (error) +- break; ++ goto del_cursor; + + /* + * Loop through inode btree records in this ag, +@@ -454,7 +454,7 @@ xfs_bulkstat( + error = xfs_inobt_get_rec(cur, &r, &i); + if (error || i == 0) { + end_of_ag = 1; +- break; ++ goto del_cursor; + } + + /* +@@ -476,13 +476,17 @@ xfs_bulkstat( + error = xfs_btree_increment(cur, 0, &tmp); + cond_resched(); + } ++ + /* +- * Drop the btree buffers and the agi buffer. +- * We can't hold any of the locks these represent +- * when calling iget. ++ * Drop the btree buffers and the agi buffer as we can't hold any ++ * of the locks these represent when calling iget. If there is a ++ * pending error, then we are done. + */ ++del_cursor: + xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); + xfs_buf_relse(agbp); ++ if (error) ++ break; + /* + * Now format all the good inodes into the user's buffer. + */ diff --git a/queue-3.17/xfs-bulkstat-error-handling-is-broken.patch b/queue-3.17/xfs-bulkstat-error-handling-is-broken.patch new file mode 100644 index 00000000000..3cb55de1d49 --- /dev/null +++ b/queue-3.17/xfs-bulkstat-error-handling-is-broken.patch @@ -0,0 +1,120 @@ +From febe3cbe38b0bc0a925906dc90e8d59048851f87 Mon Sep 17 00:00:00 2001 +From: Dave Chinner +Date: Fri, 7 Nov 2014 08:31:15 +1100 +Subject: xfs: bulkstat error handling is broken + +From: Dave Chinner + +commit febe3cbe38b0bc0a925906dc90e8d59048851f87 upstream. + +The error propagation is a horror - xfs_bulkstat() returns +a rval variable which is only set if there are formatter errors. Any +sort of btree walk error or corruption will cause the bulkstat walk +to terminate but will not pass an error back to userspace. Worse +is the fact that formatter errors will also be ignored if any inodes +were correctly formatted into the user buffer. + +Hence bulkstat can fail badly yet still report success to userspace. +This causes significant issues with xfsdump not dumping everything +in the filesystem yet reporting success. It's not until a restore +fails that there is any indication that the dump was bad and tha +bulkstat failed. This patch now triggers xfsdump to fail with +bulkstat errors rather than silently missing files in the dump. + +This now causes bulkstat to fail when the lastino cookie does not +fall inside an existing inode chunk. The pre-3.17 code tolerated +that error by allowing the code to move to the next inode chunk +as the agino target is guaranteed to fall into the next btree +record. + +With the fixes up to this point in the series, xfsdump now passes on +the troublesome filesystem image that exposes all these bugs. + +Signed-off-by: Dave Chinner +Reviewed-by: Brian Foster +Signed-off-by: Greg Kroah-Hartman + +--- + fs/xfs/xfs_itable.c | 29 +++++++++++++++++++---------- + 1 file changed, 19 insertions(+), 10 deletions(-) + +--- a/fs/xfs/xfs_itable.c ++++ b/fs/xfs/xfs_itable.c +@@ -236,8 +236,10 @@ xfs_bulkstat_grab_ichunk( + XFS_WANT_CORRUPTED_RETURN(stat == 1); + + /* Check if the record contains the inode in request */ +- if (irec->ir_startino + XFS_INODES_PER_CHUNK <= agino) +- return -EINVAL; ++ if (irec->ir_startino + XFS_INODES_PER_CHUNK <= agino) { ++ *icount = 0; ++ return 0; ++ } + + idx = agino - irec->ir_startino + 1; + if (idx < XFS_INODES_PER_CHUNK && +@@ -352,7 +354,6 @@ xfs_bulkstat( + xfs_inobt_rec_incore_t *irbuf; /* start of irec buffer */ + xfs_ino_t lastino; /* last inode number returned */ + int nirbuf; /* size of irbuf */ +- int rval; /* return value error code */ + int ubcount; /* size of user's buffer */ + struct xfs_bulkstat_agichunk ac; + int error = 0; +@@ -388,7 +389,6 @@ xfs_bulkstat( + * Loop over the allocation groups, starting from the last + * inode returned; 0 means start of the allocation group. + */ +- rval = 0; + while (agno < mp->m_sb.sb_agcount) { + struct xfs_inobt_rec_incore *irbp = irbuf; + struct xfs_inobt_rec_incore *irbufend = irbuf + nirbuf; +@@ -491,13 +491,16 @@ del_cursor: + formatter, statstruct_size, &ac, + &lastino); + if (error) +- rval = error; ++ break; + + cond_resched(); + } + +- /* If we've run out of space, we are done */ +- if (ac.ac_ubleft < statstruct_size) ++ /* ++ * If we've run out of space or had a formatting error, we ++ * are now done ++ */ ++ if (ac.ac_ubleft < statstruct_size || error) + break; + + if (end_of_ag) { +@@ -511,11 +514,17 @@ del_cursor: + */ + kmem_free(irbuf); + *ubcountp = ac.ac_ubelem; ++ + /* +- * Found some inodes, return them now and return the error next time. ++ * We found some inodes, so clear the error status and return them. ++ * The lastino pointer will point directly at the inode that triggered ++ * any error that occurred, so on the next call the error will be ++ * triggered again and propagated to userspace as there will be no ++ * formatted inodes in the buffer. + */ + if (ac.ac_ubelem) +- rval = 0; ++ error = 0; ++ + if (agno >= mp->m_sb.sb_agcount) { + /* + * If we ran out of filesystem, mark lastino as off +@@ -527,7 +536,7 @@ del_cursor: + } else + *lastinop = (xfs_ino_t)lastino; + +- return rval; ++ return error; + } + + int diff --git a/queue-3.17/xfs-bulkstat-main-loop-logic-is-a-mess.patch b/queue-3.17/xfs-bulkstat-main-loop-logic-is-a-mess.patch new file mode 100644 index 00000000000..ad3f3e5adb6 --- /dev/null +++ b/queue-3.17/xfs-bulkstat-main-loop-logic-is-a-mess.patch @@ -0,0 +1,150 @@ +From 6e57c542cb7e0e580eb53ae76a77875c7d92b4b1 Mon Sep 17 00:00:00 2001 +From: Dave Chinner +Date: Fri, 7 Nov 2014 08:31:13 +1100 +Subject: xfs: bulkstat main loop logic is a mess + +From: Dave Chinner + +commit 6e57c542cb7e0e580eb53ae76a77875c7d92b4b1 upstream. + +There are a bunch of variables tha tare more wildy scoped than they +need to be, obfuscated user buffer checks and tortured "next inode" +tracking. This all needs cleaning up to expose the real issues that +need fixing. + +Signed-off-by: Dave Chinner +Reviewed-by: Brian Foster +Signed-off-by: Dave Chinner +Signed-off-by: Greg Kroah-Hartman + +--- + fs/xfs/xfs_itable.c | 56 ++++++++++++++++++++++------------------------------ + 1 file changed, 24 insertions(+), 32 deletions(-) + +--- a/fs/xfs/xfs_itable.c ++++ b/fs/xfs/xfs_itable.c +@@ -348,30 +348,23 @@ xfs_bulkstat( + xfs_agino_t agino; /* inode # in allocation group */ + xfs_agnumber_t agno; /* allocation group number */ + xfs_btree_cur_t *cur; /* btree cursor for ialloc btree */ +- int end_of_ag; /* set if we've seen the ag end */ +- int error; /* error code */ +- int icount; /* count of inodes good in irbuf */ + size_t irbsize; /* size of irec buffer in bytes */ +- xfs_ino_t ino; /* inode number (filesystem) */ +- xfs_inobt_rec_incore_t *irbp; /* current irec buffer pointer */ + xfs_inobt_rec_incore_t *irbuf; /* start of irec buffer */ +- xfs_inobt_rec_incore_t *irbufend; /* end of good irec buffer entries */ + xfs_ino_t lastino; /* last inode number returned */ + int nirbuf; /* size of irbuf */ + int rval; /* return value error code */ + int ubcount; /* size of user's buffer */ +- int stat; + struct xfs_bulkstat_agichunk ac; ++ int error = 0; + + /* + * Get the last inode value, see if there's nothing to do. + */ +- ino = (xfs_ino_t)*lastinop; +- lastino = ino; +- agno = XFS_INO_TO_AGNO(mp, ino); +- agino = XFS_INO_TO_AGINO(mp, ino); ++ lastino = *lastinop; ++ agno = XFS_INO_TO_AGNO(mp, lastino); ++ agino = XFS_INO_TO_AGINO(mp, lastino); + if (agno >= mp->m_sb.sb_agcount || +- ino != XFS_AGINO_TO_INO(mp, agno, agino)) { ++ lastino != XFS_AGINO_TO_INO(mp, agno, agino)) { + *done = 1; + *ubcountp = 0; + return 0; +@@ -396,8 +389,13 @@ xfs_bulkstat( + * inode returned; 0 means start of the allocation group. + */ + rval = 0; +- while (XFS_BULKSTAT_UBLEFT(ac.ac_ubleft) && agno < mp->m_sb.sb_agcount) { +- cond_resched(); ++ while (agno < mp->m_sb.sb_agcount) { ++ struct xfs_inobt_rec_incore *irbp = irbuf; ++ struct xfs_inobt_rec_incore *irbufend = irbuf + nirbuf; ++ bool end_of_ag = false; ++ int icount = 0; ++ int stat; ++ + error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); + if (error) + break; +@@ -407,10 +405,6 @@ xfs_bulkstat( + */ + cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno, + XFS_BTNUM_INO); +- irbp = irbuf; +- irbufend = irbuf + nirbuf; +- end_of_ag = 0; +- icount = 0; + if (agino > 0) { + /* + * In the middle of an allocation group, we need to get +@@ -435,7 +429,7 @@ xfs_bulkstat( + error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &stat); + } + if (error || stat == 0) { +- end_of_ag = 1; ++ end_of_ag = true; + goto del_cursor; + } + +@@ -448,7 +442,7 @@ xfs_bulkstat( + + error = xfs_inobt_get_rec(cur, &r, &stat); + if (error || stat == 0) { +- end_of_ag = 1; ++ end_of_ag = true; + goto del_cursor; + } + +@@ -470,7 +464,7 @@ xfs_bulkstat( + agino = r.ir_startino + XFS_INODES_PER_CHUNK; + error = xfs_btree_increment(cur, 0, &stat); + if (error || stat == 0) { +- end_of_ag = 1; ++ end_of_ag = true; + goto del_cursor; + } + cond_resched(); +@@ -491,7 +485,7 @@ del_cursor: + */ + irbufend = irbp; + for (irbp = irbuf; +- irbp < irbufend && XFS_BULKSTAT_UBLEFT(ac.ac_ubleft); ++ irbp < irbufend && ac.ac_ubleft >= statstruct_size; + irbp++) { + error = xfs_bulkstat_ag_ichunk(mp, agno, irbp, + formatter, statstruct_size, &ac, +@@ -502,17 +496,15 @@ del_cursor: + cond_resched(); + } + +- /* +- * Set up for the next loop iteration. +- */ +- if (XFS_BULKSTAT_UBLEFT(ac.ac_ubleft)) { +- if (end_of_ag) { +- agno++; +- agino = 0; +- } else +- agino = XFS_INO_TO_AGINO(mp, lastino); +- } else ++ /* If we've run out of space, we are done */ ++ if (ac.ac_ubleft < statstruct_size) + break; ++ ++ if (end_of_ag) { ++ agno++; ++ agino = 0; ++ } else ++ agino = XFS_INO_TO_AGINO(mp, lastino); + } + /* + * Done, we're either out of filesystem or space to put the data. diff --git a/queue-3.17/xfs-check-error-during-inode-btree-iteration-in-xfs_bulkstat.patch b/queue-3.17/xfs-check-error-during-inode-btree-iteration-in-xfs_bulkstat.patch new file mode 100644 index 00000000000..f12c1ddc4d7 --- /dev/null +++ b/queue-3.17/xfs-check-error-during-inode-btree-iteration-in-xfs_bulkstat.patch @@ -0,0 +1,38 @@ +From 7a19dee116c8fae7ba7a778043c245194289f5a2 Mon Sep 17 00:00:00 2001 +From: Jan Kara +Date: Thu, 30 Oct 2014 10:34:52 +1100 +Subject: xfs: Check error during inode btree iteration in xfs_bulkstat() + +From: Jan Kara + +commit 7a19dee116c8fae7ba7a778043c245194289f5a2 upstream. + +xfs_bulkstat() doesn't check error return from xfs_btree_increment(). In +case of specific fs corruption that could result in xfs_bulkstat() +entering an infinite loop because we would be looping over the same +chunk over and over again. Fix the problem by checking the return value +and terminating the loop properly. + +Coverity-id: 1231338 +Signed-off-by: Jan Kara +Reviewed-by: Jie Liu +Signed-off-by: Dave Chinner +Signed-off-by: Greg Kroah-Hartman + +--- + fs/xfs/xfs_itable.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/fs/xfs/xfs_itable.c ++++ b/fs/xfs/xfs_itable.c +@@ -474,6 +474,10 @@ xfs_bulkstat( + */ + agino = r.ir_startino + XFS_INODES_PER_CHUNK; + error = xfs_btree_increment(cur, 0, &tmp); ++ if (error) { ++ end_of_ag = 1; ++ goto del_cursor; ++ } + cond_resched(); + } + diff --git a/queue-3.17/xfs-track-bulkstat-progress-by-agino.patch b/queue-3.17/xfs-track-bulkstat-progress-by-agino.patch new file mode 100644 index 00000000000..b2d7ec6bb5d --- /dev/null +++ b/queue-3.17/xfs-track-bulkstat-progress-by-agino.patch @@ -0,0 +1,198 @@ +From 002758992693ae63c04122603ea9261a0a58d728 Mon Sep 17 00:00:00 2001 +From: Dave Chinner +Date: Fri, 7 Nov 2014 08:33:52 +1100 +Subject: xfs: track bulkstat progress by agino + +From: Dave Chinner + +commit 002758992693ae63c04122603ea9261a0a58d728 upstream. + +The bulkstat main loop progress is tracked by the "lastino" +variable, which is a full 64 bit inode. However, the loop actually +works on agno/agino pairs, and so there's a significant disconnect +between the rest of the loop and the main cursor. Convert this to +use the agino, and pass the agino into the chunk formatting function +and convert it too. + +This gets rid of the inconsistency in the loop processing, and +finally makes it simple for us to skip inodes at any point in the +loop simply by incrementing the agino cursor. + +Signed-off-by: Dave Chinner +Reviewed-by: Brian Foster +Signed-off-by: Dave Chinner +Signed-off-by: Greg Kroah-Hartman + +--- + fs/xfs/xfs_itable.c | 71 ++++++++++++++++++++++++---------------------------- + 1 file changed, 34 insertions(+), 37 deletions(-) + +--- a/fs/xfs/xfs_itable.c ++++ b/fs/xfs/xfs_itable.c +@@ -282,30 +282,31 @@ xfs_bulkstat_ag_ichunk( + bulkstat_one_pf formatter, + size_t statstruct_size, + struct xfs_bulkstat_agichunk *acp, +- xfs_ino_t *lastino) ++ xfs_agino_t *last_agino) + { + char __user **ubufp = acp->ac_ubuffer; + int chunkidx; + int error = 0; +- xfs_agino_t agino; ++ xfs_agino_t agino = irbp->ir_startino; + +- agino = irbp->ir_startino; + for (chunkidx = 0; chunkidx < XFS_INODES_PER_CHUNK; + chunkidx++, agino++) { + int fmterror; + int ubused; +- xfs_ino_t ino = XFS_AGINO_TO_INO(mp, agno, agino); ++ ++ /* inode won't fit in buffer, we are done */ ++ if (acp->ac_ubleft < statstruct_size) ++ break; + + /* Skip if this inode is free */ +- if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free) { +- *lastino = ino; ++ if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free) + continue; +- } + + /* Get the inode and fill in a single buffer */ + ubused = statstruct_size; +- error = formatter(mp, ino, *ubufp, acp->ac_ubleft, +- &ubused, &fmterror); ++ error = formatter(mp, XFS_AGINO_TO_INO(mp, agno, agino), ++ *ubufp, acp->ac_ubleft, &ubused, &fmterror); ++ + if (fmterror == BULKSTAT_RV_GIVEUP || + (error && error != -ENOENT && error != -EINVAL)) { + acp->ac_ubleft = 0; +@@ -315,7 +316,6 @@ xfs_bulkstat_ag_ichunk( + + /* be careful not to leak error if at end of chunk */ + if (fmterror == BULKSTAT_RV_NOTHING || error) { +- *lastino = ino; + error = 0; + continue; + } +@@ -323,12 +323,18 @@ xfs_bulkstat_ag_ichunk( + *ubufp += ubused; + acp->ac_ubleft -= ubused; + acp->ac_ubelem++; +- *lastino = ino; +- +- if (acp->ac_ubleft < statstruct_size) +- break; + } + ++ /* ++ * Post-update *last_agino. At this point, agino will always point one ++ * inode past the last inode we processed successfully. Hence we ++ * substract that inode when setting the *last_agino cursor so that we ++ * return the correct cookie to userspace. On the next bulkstat call, ++ * the inode under the lastino cookie will be skipped as we have already ++ * processed it here. ++ */ ++ *last_agino = agino - 1; ++ + return error; + } + +@@ -352,7 +358,6 @@ xfs_bulkstat( + xfs_btree_cur_t *cur; /* btree cursor for ialloc btree */ + size_t irbsize; /* size of irec buffer in bytes */ + xfs_inobt_rec_incore_t *irbuf; /* start of irec buffer */ +- xfs_ino_t lastino; /* last inode number returned */ + int nirbuf; /* size of irbuf */ + int ubcount; /* size of user's buffer */ + struct xfs_bulkstat_agichunk ac; +@@ -361,11 +366,10 @@ xfs_bulkstat( + /* + * Get the last inode value, see if there's nothing to do. + */ +- lastino = *lastinop; +- agno = XFS_INO_TO_AGNO(mp, lastino); +- agino = XFS_INO_TO_AGINO(mp, lastino); ++ agno = XFS_INO_TO_AGNO(mp, *lastinop); ++ agino = XFS_INO_TO_AGINO(mp, *lastinop); + if (agno >= mp->m_sb.sb_agcount || +- lastino != XFS_AGINO_TO_INO(mp, agno, agino)) { ++ *lastinop != XFS_AGINO_TO_INO(mp, agno, agino)) { + *done = 1; + *ubcountp = 0; + return 0; +@@ -420,7 +424,6 @@ xfs_bulkstat( + irbp->ir_freecount = r.ir_freecount; + irbp->ir_free = r.ir_free; + irbp++; +- agino = r.ir_startino + XFS_INODES_PER_CHUNK; + } + /* Increment to the next record */ + error = xfs_btree_increment(cur, 0, &stat); +@@ -458,10 +461,6 @@ xfs_bulkstat( + irbp++; + icount += XFS_INODES_PER_CHUNK - r.ir_freecount; + } +- /* +- * Set agino to after this chunk and bump the cursor. +- */ +- agino = r.ir_startino + XFS_INODES_PER_CHUNK; + error = xfs_btree_increment(cur, 0, &stat); + if (error || stat == 0) { + end_of_ag = true; +@@ -481,7 +480,9 @@ del_cursor: + if (error) + break; + /* +- * Now format all the good inodes into the user's buffer. ++ * Now format all the good inodes into the user's buffer. The ++ * call to xfs_bulkstat_ag_ichunk() sets up the agino pointer ++ * for the next loop iteration. + */ + irbufend = irbp; + for (irbp = irbuf; +@@ -489,7 +490,7 @@ del_cursor: + irbp++) { + error = xfs_bulkstat_ag_ichunk(mp, agno, irbp, + formatter, statstruct_size, &ac, +- &lastino); ++ &agino); + if (error) + break; + +@@ -506,8 +507,7 @@ del_cursor: + if (end_of_ag) { + agno++; + agino = 0; +- } else +- agino = XFS_INO_TO_AGINO(mp, lastino); ++ } + } + /* + * Done, we're either out of filesystem or space to put the data. +@@ -525,16 +525,13 @@ del_cursor: + if (ac.ac_ubelem) + error = 0; + +- if (agno >= mp->m_sb.sb_agcount) { +- /* +- * If we ran out of filesystem, mark lastino as off +- * the end of the filesystem, so the next call +- * will return immediately. +- */ +- *lastinop = (xfs_ino_t)XFS_AGINO_TO_INO(mp, agno, 0); ++ /* ++ * If we ran out of filesystem, lastino will point off the end of ++ * the filesystem so the next call will return immediately. ++ */ ++ *lastinop = XFS_AGINO_TO_INO(mp, agno, agino); ++ if (agno >= mp->m_sb.sb_agcount) + *done = 1; +- } else +- *lastinop = (xfs_ino_t)lastino; + + return error; + }