5.15.46-rc1 review
Subsystems (2)
Greg Kroah-Hartman
maintainerPATCH 575/667 selftests/landlock: Make tests build with old libc
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 87129ef13603ae46c82bcd09eed948acf0506dbb upstream.
Replace SYS_<syscall> with __NR_<syscall>. Using the __NR_<syscall> notation, provided by UAPI, is useful to build tests on systems without the SYS_<syscall> definitions.
Replace SYS_pivot_root with __NR_pivot_root, and SYS_move_mount with __NR_move_mount.
Define renameat2() and RENAME_EXCHANGE if they are unknown to old build systems.
--- tools/testing/selftests/landlock/fs_test.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-)
tools/testing/selftests/landlock/fs_test.c +18 -5
@@ -22,6 +22,19 @@#include "common.h" +#ifndef renameat2 +int renameat2 (int olddirfd,const char *oldpath,int newdirfd, +const char *newpath,unsigned int flags) +{ +return syscall (__NR_renameat2, olddirfd, oldpath, newdirfd, newpath, + flags); +} +#endif + +#ifndef RENAME_EXCHANGE +#define RENAME_EXCHANGE (1 << 1) +#endif +#define TMP_DIR "tmp"#define BINARY_PATH "./true"
@@ -1279,7 +1292,7 @@ TEST_F_FORK(layout1, rule_inside_mount_nint ruleset_fd;set_cap (_metadata,CAP_SYS_ADMIN ); - ASSERT_EQ(0, syscall(SYS_pivot_root, dir_s3d2, dir_s3d3)) + ASSERT_EQ(0, syscall(__NR_pivot_root, dir_s3d2, dir_s3d3)) {TH_LOG ("Failed to pivot root: %s" ,strerror (errno)); };
@@ -1313,7 +1326,7 @@ TEST_F_FORK(layout1, mount_and_pivot)set_cap (_metadata,CAP_SYS_ADMIN );ASSERT_EQ (-1 ,mount (NULL , dir_s3d2,NULL ,MS_RDONLY ,NULL ));ASSERT_EQ (EPERM , errno); -ASSERT_EQ (-1 ,syscall (SYS_pivot_root, dir_s3d2, dir_s3d3)); +ASSERT_EQ (-1 ,syscall (__NR_pivot_root, dir_s3d2, dir_s3d3));ASSERT_EQ (EPERM , errno);clear_cap (_metadata,CAP_SYS_ADMIN ); }
@@ -1332,13 +1345,13 @@ TEST_F_FORK(layout1, move_mount)ASSERT_LE (0 , ruleset_fd);set_cap (_metadata,CAP_SYS_ADMIN ); -ASSERT_EQ (0 ,syscall (SYS_move_mount,AT_FDCWD , dir_s3d2,AT_FDCWD , +ASSERT_EQ (0 ,syscall (__NR_move_mount,AT_FDCWD , dir_s3d2,AT_FDCWD , dir_s1d2, 0)) {TH_LOG ("Failed to move mount: %s" ,strerror (errno)); } -ASSERT_EQ (0 ,syscall (SYS_move_mount,AT_FDCWD , dir_s1d2,AT_FDCWD , +ASSERT_EQ (0 ,syscall (__NR_move_mount,AT_FDCWD , dir_s1d2,AT_FDCWD , dir_s3d2,0 ));clear_cap (_metadata,CAP_SYS_ADMIN );
@@ -1346,7 +1359,7 @@ TEST_F_FORK(layout1, move_mount)ASSERT_EQ (0 ,close (ruleset_fd));set_cap (_metadata,CAP_SYS_ADMIN ); -ASSERT_EQ (-1 ,syscall (SYS_move_mount,AT_FDCWD , dir_s3d2,AT_FDCWD , +ASSERT_EQ (-1 ,syscall (__NR_move_mount,AT_FDCWD , dir_s3d2,AT_FDCWD , dir_s1d2,0 ));ASSERT_EQ (EPERM , errno);clear_cap (_metadata,CAP_SYS_ADMIN );
Greg Kroah-Hartman
maintainerPATCH 576/667 selftests/landlock: Extend tests for minimal valid attribute size
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 291865bd7e8bb4b4033d341fa02dafa728e6378c upstream.
This might be useful when the struct landlock_ruleset_attr will get more fields.
--- tools/testing/selftests/landlock/base_test.c | 5 +++++ 1 file changed, 5 insertions(+)
tools/testing/selftests/landlock/base_test.c +5 -0
@@ -35,6 +35,8 @@ TEST(inconsistent_attr)ASSERT_EQ (EINVAL , errno);ASSERT_EQ (-1 ,landlock_create_ruleset (ruleset_attr,1 ,0 ));ASSERT_EQ (EINVAL , errno); +ASSERT_EQ (-1 ,landlock_create_ruleset (ruleset_attr,7 ,0 )); +ASSERT_EQ (EINVAL , errno);ASSERT_EQ (-1 ,landlock_create_ruleset (NULL ,1 ,0 ));/* The size if less than sizeof(struct landlock_attr_enforce). */
@@ -47,6 +49,9 @@ TEST(inconsistent_attr)ASSERT_EQ (-1 ,landlock_create_ruleset (ruleset_attr, page_size +1 ,0 ));ASSERT_EQ (E2BIG , errno); +/* Checks minimal valid attribute size. */ +ASSERT_EQ (-1 ,landlock_create_ruleset (ruleset_attr,8 ,0 )); +ASSERT_EQ (ENOMSG , errno);ASSERT_EQ (-1 ,landlock_create_ruleset ( ruleset_attr,sizeof (struct landlock_ruleset_attr ),0 ));
Greg Kroah-Hartman
maintainerPATCH 577/667 selftests/landlock: Add tests for unknown access rights
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit c56b3bf566da5a0dd3b58ad97a614b0928b06ebf upstream.
Make sure that trying to use unknown access rights returns an error.
--- tools/testing/selftests/landlock/fs_test.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
tools/testing/selftests/landlock/fs_test.c +16 -0
@@ -448,6 +448,22 @@ TEST_F_FORK(layout1, file_access_rights)ASSERT_EQ (0 ,close (path_beneath.parent_fd)); } +TEST_F_FORK(layout1, unknown_access_rights) +{ +__u64 access_mask; + +for (access_mask =1ULL <<63 ; access_mask !=ACCESS_LAST ; + access_mask >>=1 ) { +struct landlock_ruleset_attr ruleset_attr = { + .handled_access_fs = access_mask, + }; + +ASSERT_EQ (-1 ,landlock_create_ruleset (&ruleset_attr, +sizeof (ruleset_attr),0 )); +ASSERT_EQ (EINVAL , errno); + } +} +static void add_path_beneath (struct __test_metadata *const _metadata,const int ruleset_fd,const __u64 allowed_access,const char *const path)
Greg Kroah-Hartman
maintainerPATCH 578/667 selftests/landlock: Extend access right tests to directories
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit d18955d094d09a220cf8f533f5e896a2fe31575a upstream.
Make sure that all filesystem access rights can be tied to directories.
Rename layout1.file_access_rights to layout1.file_and_dir_access_rights to reflect this change.
--- tools/testing/selftests/landlock/fs_test.c | 30 +++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-)
tools/testing/selftests/landlock/fs_test.c +22 -8
@@ -418,11 +418,12 @@ TEST_F_FORK(layout1, inval)/* clang-format on */ -TEST_F_FORK(layout1, file_access_rights) +TEST_F_FORK(layout1, file_and_dir_access_rights) {__u64 access;int err; -struct landlock_path_beneath_attr path_beneath = {}; +struct landlock_path_beneath_attr path_beneath_file = {}, + path_beneath_dir = {};struct landlock_ruleset_attr ruleset_attr = { .handled_access_fs =ACCESS_ALL , };
@@ -432,20 +433,33 @@ TEST_F_FORK(layout1, file_access_rights)ASSERT_LE (0 , ruleset_fd);/* Tests access rights for files. */ - path_beneath.parent_fd =open (file1_s1d2,O_PATH |O_CLOEXEC ); -ASSERT_LE (0 , path_beneath.parent_fd); + path_beneath_file.parent_fd =open (file1_s1d2,O_PATH |O_CLOEXEC ); +ASSERT_LE (0 , path_beneath_file.parent_fd); + +/* Tests access rights for directories. */ + path_beneath_dir.parent_fd = +open (dir_s1d2,O_PATH |O_DIRECTORY |O_CLOEXEC ); +ASSERT_LE (0 , path_beneath_dir.parent_fd); +for (access =1 ; access <=ACCESS_LAST ; access <<=1 ) { - path_beneath.allowed_access = access; + path_beneath_dir.allowed_access = access; +ASSERT_EQ (0 ,landlock_add_rule (ruleset_fd, +LANDLOCK_RULE_PATH_BENEATH , + &path_beneath_dir,0 )); + + path_beneath_file.allowed_access = access; err =landlock_add_rule (ruleset_fd,LANDLOCK_RULE_PATH_BENEATH , - &path_beneath,0 ); -if ((access |ACCESS_FILE ) ==ACCESS_FILE ) { + &path_beneath_file,0 ); +if (access &ACCESS_FILE ) {ASSERT_EQ (0 , err); }else {ASSERT_EQ (-1 , err);ASSERT_EQ (EINVAL , errno); } } -ASSERT_EQ (0 ,close (path_beneath.parent_fd)); +ASSERT_EQ (0 ,close (path_beneath_file.parent_fd)); +ASSERT_EQ (0 ,close (path_beneath_dir.parent_fd)); +ASSERT_EQ (0 ,close (ruleset_fd)); }TEST_F_FORK (layout1, unknown_access_rights)
Greg Kroah-Hartman
maintainerPATCH 579/667 selftests/landlock: Fully test file rename with "remove" access
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 6a1bdd4a0bfc30fa4fa2b3a979e6525f28996db9 upstream.
These tests were missing to check the check_access_path() call with all combinations of maybe_remove(old_dentry) and maybe_remove(new_dentry).
Extend layout1.link with a new complementary test and check that REMOVE_FILE is not required to link a file.
--- tools/testing/selftests/landlock/fs_test.c | 41 ++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 4 deletions(-)
tools/testing/selftests/landlock/fs_test.c +37 -4
@@ -1659,15 +1659,21 @@ TEST_F_FORK(layout1, execute) TEST_F_FORK(layout1, link) { -const struct rule rules[] = { +const struct rule layer1[] = { { .path = dir_s1d2, .access =LANDLOCK_ACCESS_FS_MAKE_REG , }, {}, }; -const int ruleset_fd = -create_ruleset (_metadata, rules[0 ].access, rules); +const struct rule layer2[] = { + { + .path = dir_s1d3, + .access =LANDLOCK_ACCESS_FS_REMOVE_FILE , + }, + {}, + }; +int ruleset_fd =create_ruleset (_metadata, layer1[0 ].access, layer1);ASSERT_LE (0 , ruleset_fd);
@@ -1680,14 +1686,30 @@ TEST_F_FORK(layout1, link)ASSERT_EQ (-1 ,link (file2_s1d1, file1_s1d1));ASSERT_EQ (EACCES , errno); +/* Denies linking because of reparenting. */ ASSERT_EQ (-1 ,link (file1_s2d1, file1_s1d2));ASSERT_EQ (EXDEV , errno);ASSERT_EQ (-1 ,link (file2_s1d2, file1_s1d3));ASSERT_EQ (EXDEV , errno); +ASSERT_EQ (-1 ,link (file2_s1d3, file1_s1d2)); +ASSERT_EQ (EXDEV , errno);ASSERT_EQ (0 ,link (file2_s1d2, file1_s1d2));ASSERT_EQ (0 ,link (file2_s1d3, file1_s1d3)); + +/* Prepares for next unlinks. */ +ASSERT_EQ (0 ,unlink (file2_s1d2)); +ASSERT_EQ (0 ,unlink (file2_s1d3)); + + ruleset_fd =create_ruleset (_metadata, layer2[0 ].access, layer2); +ASSERT_LE (0 , ruleset_fd); +enforce_ruleset (_metadata, ruleset_fd); +ASSERT_EQ (0 ,close (ruleset_fd)); + +/* Checks that linkind doesn't require the ability to delete a file. */ +ASSERT_EQ (0 ,link (file1_s1d2, file2_s1d2)); +ASSERT_EQ (0 ,link (file1_s1d3, file2_s1d3)); }TEST_F_FORK (layout1, rename_file)
@@ -1708,7 +1730,6 @@ TEST_F_FORK(layout1, rename_file)ASSERT_LE (0 , ruleset_fd); -ASSERT_EQ (0 ,unlink (file1_s1d1));ASSERT_EQ (0 ,unlink (file1_s1d2));enforce_ruleset (_metadata, ruleset_fd);
@@ -1744,9 +1765,15 @@ TEST_F_FORK(layout1, rename_file)ASSERT_EQ (-1 ,renameat2 (AT_FDCWD , dir_s2d2,AT_FDCWD , file1_s2d1,RENAME_EXCHANGE ));ASSERT_EQ (EACCES , errno); +/* Checks that file1_s2d1 cannot be removed (instead of ENOTDIR). */ +ASSERT_EQ (-1 ,rename (dir_s2d2, file1_s2d1)); +ASSERT_EQ (EACCES , errno);ASSERT_EQ (-1 ,renameat2 (AT_FDCWD , file1_s2d1,AT_FDCWD , dir_s2d2,RENAME_EXCHANGE ));ASSERT_EQ (EACCES , errno); +/* Checks that file1_s1d1 cannot be removed (instead of EISDIR). */ +ASSERT_EQ (-1 ,rename (file1_s1d1, dir_s1d2)); +ASSERT_EQ (EACCES , errno);/* Renames files with different parents. */ ASSERT_EQ (-1 ,rename (file1_s2d2, file1_s1d2));
@@ -1809,9 +1836,15 @@ TEST_F_FORK(layout1, rename_dir)ASSERT_EQ (-1 ,renameat2 (AT_FDCWD , dir_s1d1,AT_FDCWD , dir_s2d1,RENAME_EXCHANGE ));ASSERT_EQ (EACCES , errno); +/* Checks that dir_s1d2 cannot be removed (instead of ENOTDIR). */ +ASSERT_EQ (-1 ,rename (dir_s1d2, file1_s1d1)); +ASSERT_EQ (EACCES , errno);ASSERT_EQ (-1 ,renameat2 (AT_FDCWD , file1_s1d1,AT_FDCWD , dir_s1d2,RENAME_EXCHANGE ));ASSERT_EQ (EACCES , errno); +/* Checks that dir_s1d2 cannot be removed (instead of EISDIR). */ +ASSERT_EQ (-1 ,rename (file1_s1d1, dir_s1d2)); +ASSERT_EQ (EACCES , errno);/* * Exchanges and renames directory to the same parent, which allows
Greg Kroah-Hartman
maintainerPATCH 580/667 selftests/landlock: Add tests for O_PATH
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit d1788ad990874734341b05ab8ccb6448c09c6422 upstream.
The O_PATH flag is currently not handled by Landlock. Let's make sure this behavior will remain consistent with the same ruleset over time.
--- tools/testing/selftests/landlock/fs_test.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
tools/testing/selftests/landlock/fs_test.c +8 -2
@@ -654,17 +654,23 @@ TEST_F_FORK(layout1, effective_access)enforce_ruleset (_metadata, ruleset_fd);ASSERT_EQ (0 ,close (ruleset_fd)); -/* Tests on a directory. */ +/* Tests on a directory (with or without O_PATH). */ ASSERT_EQ (EACCES ,test_open ("/" ,O_RDONLY )); +ASSERT_EQ (0 ,test_open ("/" ,O_RDONLY |O_PATH ));ASSERT_EQ (EACCES ,test_open (dir_s1d1,O_RDONLY )); +ASSERT_EQ (0 ,test_open (dir_s1d1,O_RDONLY |O_PATH ));ASSERT_EQ (EACCES ,test_open (file1_s1d1,O_RDONLY )); +ASSERT_EQ (0 ,test_open (file1_s1d1,O_RDONLY |O_PATH )); +ASSERT_EQ (0 ,test_open (dir_s1d2,O_RDONLY ));ASSERT_EQ (0 ,test_open (file1_s1d2,O_RDONLY ));ASSERT_EQ (0 ,test_open (dir_s1d3,O_RDONLY ));ASSERT_EQ (0 ,test_open (file1_s1d3,O_RDONLY )); -/* Tests on a file. */ +/* Tests on a file (with or without O_PATH). */ ASSERT_EQ (EACCES ,test_open (dir_s2d2,O_RDONLY )); +ASSERT_EQ (0 ,test_open (dir_s2d2,O_RDONLY |O_PATH )); +ASSERT_EQ (0 ,test_open (file1_s2d2,O_RDONLY ));/* Checks effective read and write actions. */
Greg Kroah-Hartman
maintainerPATCH 581/667 landlock: Change landlock_add_rule(2) argument check ordering
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 589172e5636c4d16c40b90e87543d43defe2d968 upstream.
This makes more sense to first check the ruleset FD and then the rule attribute. It will be useful to factor out code for other rule types.
Add inval_add_rule_arguments tests, extension of empty_path_beneath_attr tests, to also check error ordering for landlock_add_rule(2).
--- security/landlock/syscalls.c | 22 ++++++++++------- tools/testing/selftests/landlock/base_test.c | 34 +++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 11 deletions(-)
security/landlock/syscalls.c +13 -9
@@ -318,20 +318,24 @@ SYSCALL_DEFINE4(landlock_add_rule, constif (flags)return -EINVAL ; -if (rule_type !=LANDLOCK_RULE_PATH_BENEATH ) -return -EINVAL ; - -/* Copies raw user space buffer, only one type for now. */ - res =copy_from_user (&path_beneath_attr, rule_attr, -sizeof (path_beneath_attr)); -if (res) -return -EFAULT ; -/* Gets and checks the ruleset. */ ruleset =get_ruleset_from_fd (ruleset_fd,FMODE_CAN_WRITE );if (IS_ERR (ruleset))return PTR_ERR (ruleset); +if (rule_type !=LANDLOCK_RULE_PATH_BENEATH ) { + err = -EINVAL ; + goto out_put_ruleset; + } + +/* Copies raw user space buffer, only one type for now. */ + res =copy_from_user (&path_beneath_attr, rule_attr, +sizeof (path_beneath_attr)); +if (res) { + err = -EFAULT ; + goto out_put_ruleset; + } +/* * Informs about useless rule: empty allowed_access (i.e. deny rules) * are ignored in path walks.
tools/testing/selftests/landlock/base_test.c +32 -2
@@ -121,20 +121,50 @@ TEST(inval_create_ruleset_flags)ASSERT_EQ (EINVAL , errno); } -TEST (empty_path_beneath_attr) +/* Tests ordering of syscall argument checks. */ +TEST (add_rule_checks_ordering) {const struct landlock_ruleset_attr ruleset_attr = { .handled_access_fs =LANDLOCK_ACCESS_FS_EXECUTE , }; +struct landlock_path_beneath_attr path_beneath_attr = { + .allowed_access =LANDLOCK_ACCESS_FS_EXECUTE , + .parent_fd =-1 , + };const int ruleset_fd =landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr),0 );ASSERT_LE (0 , ruleset_fd); -/* Similar to struct landlock_path_beneath_attr.parent_fd = 0 */ +/* Checks invalid flags. */ +ASSERT_EQ (-1 ,landlock_add_rule (-1 ,0 ,NULL ,1 )); +ASSERT_EQ (EINVAL , errno); + +/* Checks invalid ruleset FD. */ +ASSERT_EQ (-1 ,landlock_add_rule (-1 ,0 ,NULL ,0 )); +ASSERT_EQ (EBADF , errno); + +/* Checks invalid rule type. */ +ASSERT_EQ (-1 ,landlock_add_rule (ruleset_fd,0 ,NULL ,0 )); +ASSERT_EQ (EINVAL , errno); + +/* Checks invalid rule attr. */ ASSERT_EQ (-1 ,landlock_add_rule (ruleset_fd,LANDLOCK_RULE_PATH_BENEATH ,NULL ,0 ));ASSERT_EQ (EFAULT , errno); + +/* Checks invalid path_beneath.parent_fd. */ +ASSERT_EQ (-1 ,landlock_add_rule (ruleset_fd,LANDLOCK_RULE_PATH_BENEATH , + &path_beneath_attr,0 )); +ASSERT_EQ (EBADF , errno); + +/* Checks valid call. */ + path_beneath_attr.parent_fd = +open ("/tmp" ,O_PATH |O_NOFOLLOW |O_DIRECTORY |O_CLOEXEC ); +ASSERT_LE (0 , path_beneath_attr.parent_fd); +ASSERT_EQ (0 ,landlock_add_rule (ruleset_fd,LANDLOCK_RULE_PATH_BENEATH , + &path_beneath_attr,0 )); +ASSERT_EQ (0 ,close (path_beneath_attr.parent_fd));ASSERT_EQ (0 ,close (ruleset_fd)); }
Greg Kroah-Hartman
maintainerPATCH 582/667 landlock: Change landlock_restrict_self(2) check ordering
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit eba39ca4b155c54adf471a69e91799cc1727873f upstream.
According to the Landlock goal to be a security feature available to unprivileges processes, it makes more sense to first check for no_new_privs before checking anything else (i.e. syscall arguments).
Merge inval_fd_enforce and unpriv_enforce_without_no_new_privs tests into the new restrict_self_checks_ordering. This is similar to the previous commit checking other syscalls.
--- security/landlock/syscalls.c | 8 ++-- tools/testing/selftests/landlock/base_test.c | 47 +++++++++++++++++++++------ 2 files changed, 41 insertions(+), 14 deletions(-)
security/landlock/syscalls.c +4 -4
@@ -405,10 +405,6 @@ SYSCALL_DEFINE2(landlock_restrict_self,if (!landlock_initialized)return -EOPNOTSUPP ; -/* No flag for now. */ -if (flags) -return -EINVAL ; -/* * Similar checks as for seccomp(2), except that an -EPERM may be * returned.
@@ -417,6 +413,10 @@ SYSCALL_DEFINE2(landlock_restrict_self, !ns_capable_noaudit(current_user_ns(), CAP_SYS_ADMIN))return -EPERM ; +/* No flag for now. */ +if (flags) +return -EINVAL ; +/* Gets and checks the ruleset. */ ruleset =get_ruleset_from_fd (ruleset_fd,FMODE_CAN_READ );if (IS_ERR (ruleset))
tools/testing/selftests/landlock/base_test.c +37 -10
59 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 583/667 selftests/landlock: Test landlock_create_ruleset(2) argument check ordering
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 6533d0c3a86ee1cc74ff37ac92ca597deb87015c upstream.
Add inval_create_ruleset_arguments, extension of inval_create_ruleset_flags, to also check error ordering for landlock_create_ruleset(2).
This is similar to the previous commit checking landlock_add_rule(2).
Test coverage for security/landlock is 94.4% of 504 lines accorging to gcc/gcov-11.
--- tools/testing/selftests/landlock/base_test.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-)
tools/testing/selftests/landlock/base_test.c +20 -1
@@ -97,14 +97,17 @@ TEST(abi_version)ASSERT_EQ (EINVAL , errno); } -TEST (inval_create_ruleset_flags) +/* Tests ordering of syscall argument checks. */ +TEST (create_ruleset_checks_ordering) {const int last_flag =LANDLOCK_CREATE_RULESET_VERSION ;const int invalid_flag = last_flag <<1 ; +int ruleset_fd;const struct landlock_ruleset_attr ruleset_attr = { .handled_access_fs =LANDLOCK_ACCESS_FS_READ_FILE , }; +/* Checks priority for invalid flags. */ ASSERT_EQ (-1 ,landlock_create_ruleset (NULL ,0 , invalid_flag));ASSERT_EQ (EINVAL , errno);
@@ -119,6 +122,22 @@ TEST(inval_create_ruleset_flags)landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr), invalid_flag));ASSERT_EQ (EINVAL , errno); + +/* Checks too big ruleset_attr size. */ +ASSERT_EQ (-1 ,landlock_create_ruleset (&ruleset_attr,-1 ,0 )); +ASSERT_EQ (E2BIG , errno); + +/* Checks too small ruleset_attr size. */ +ASSERT_EQ (-1 ,landlock_create_ruleset (&ruleset_attr,0 ,0 )); +ASSERT_EQ (EINVAL , errno); +ASSERT_EQ (-1 ,landlock_create_ruleset (&ruleset_attr,1 ,0 )); +ASSERT_EQ (EINVAL , errno); + +/* Checks valid call. */ + ruleset_fd = +landlock_create_ruleset (&ruleset_attr,sizeof (ruleset_attr),0 ); +ASSERT_LE (0 , ruleset_fd); +ASSERT_EQ (0 ,close (ruleset_fd)); }/* Tests ordering of syscall argument checks. */
Greg Kroah-Hartman
maintainerPATCH 584/667 landlock: Define access_mask_t to enforce a consistent access mask size
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 5f2ff33e10843ef51275c8611bdb7b49537aba5d upstream.
Create and use the access_mask_t typedef to enforce a consistent access mask size and uniformly use a 16-bits type. This will helps transition to a 32-bits value one day.
Add a build check to make sure all (filesystem) access rights fit in. This will be extended with a following commit.
--- security/landlock/fs.c | 19 +++++++++++-------- security/landlock/fs.h | 2 +- security/landlock/limits.h | 2 ++ security/landlock/ruleset.c | 6 ++++-- security/landlock/ruleset.h | 16 ++++++++++++---- 5 files changed, 30 insertions(+), 15 deletions(-)
security/landlock/fs.c +11 -8
@@ -152,7 +152,8 @@ retry:* @path: Should have been checked by get_path_from_fd(). */ int landlock_append_fs_rule (struct landlock_ruleset *const ruleset, -const struct path *const path,u32 access_rights) +const struct path *const path, +access_mask_t access_rights) {int err;struct landlock_object *object;
@@ -184,7 +185,8 @@ int landlock_append_fs_rule(struct landlstatic inline u64 unmask_layers (const struct landlock_ruleset *const domain,const struct path *const path, -const u32 access_request,u64 layer_mask) +const access_mask_t access_request, +u64 layer_mask) {const struct landlock_rule *rule;const struct inode *inode;
@@ -224,7 +226,8 @@ static inline u64 unmask_layers(const st }static int check_access_path (const struct landlock_ruleset *const domain, -const struct path *const path,u32 access_request) +const struct path *const path, +const access_mask_t access_request) {bool allowed = false;struct path walker_path;
@@ -309,7 +312,7 @@ jump_up: }static inline int current_check_access_path (const struct path *const path, -const u32 access_request) +const access_mask_t access_request) {const struct landlock_ruleset *const dom =landlock_get_current_domain ();
@@ -512,7 +515,7 @@ static int hook_sb_pivotroot(const struc/* Path hooks */ -static inline u32 get_mode_access (const umode_t mode) +static inline access_mask_t get_mode_access (const umode_t mode) {switch (mode &S_IFMT ) {case S_IFLNK :
@@ -565,7 +568,7 @@ static int hook_path_link(struct dentry get_mode_access(d_backing_inode(old_dentry)->i_mode)); } -static inline u32 maybe_remove (const struct dentry *const dentry) +static inline access_mask_t maybe_remove (const struct dentry *const dentry) {if (d_is_negative (dentry))return 0 ;
@@ -635,9 +638,9 @@ static int hook_path_rmdir(const struct/* File hooks */ -static inline u32 get_file_access (const struct file *const file) +static inline access_mask_t get_file_access (const struct file *const file) { -u32 access =0 ; +access_mask_t access =0 ;if (file->f_mode &FMODE_READ ) {/* A directory can only be opened in read mode. */
security/landlock/fs.h +1 -1
@@ -66,6 +66,6 @@ __init void landlock_add_fs_hooks(void);int landlock_append_fs_rule (struct landlock_ruleset *const ruleset,const struct path *const path, -u32 access_hierarchy); +access_mask_t access_hierarchy);#endif /* _SECURITY_LANDLOCK_FS_H */
security/landlock/limits.h +2 -0
@@ -9,6 +9,7 @@#ifndef _SECURITY_LANDLOCK_LIMITS_H#define _SECURITY_LANDLOCK_LIMITS_H +#include <linux/bitops.h> #include <linux/limits.h> #include <uapi/linux/landlock.h>
@@ -19,6 +20,7 @@#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_MAKE_SYM#define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1) +#define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS)/* clang-format on */
security/landlock/ruleset.c +4 -2
@@ -45,7 +45,8 @@ static struct landlock_ruleset *create_rreturn new_ruleset; } -struct landlock_ruleset *landlock_create_ruleset (const u32 fs_access_mask) +struct landlock_ruleset * +landlock_create_ruleset (const access_mask_t fs_access_mask) {struct landlock_ruleset *new_ruleset;
@@ -228,7 +229,8 @@ static void build_check_layer(void)/* @ruleset must be locked by the caller. */ int landlock_insert_rule (struct landlock_ruleset *const ruleset, -struct landlock_object *const object,const u32 access) +struct landlock_object *const object, +const access_mask_t access) {struct landlock_layer layers[] = { { .access = access,
security/landlock/ruleset.h +12 -4
@@ -9,13 +9,20 @@#ifndef _SECURITY_LANDLOCK_RULESET_H#define _SECURITY_LANDLOCK_RULESET_H +#include <linux/bitops.h> +#include <linux/build_bug.h> #include <linux/mutex.h> #include <linux/rbtree.h> #include <linux/refcount.h> #include <linux/workqueue.h> +#include "limits.h" #include "object.h" +typedef u16 access_mask_t ; +/* Makes sure all filesystem access rights can be stored. */ +static_assert (BITS_PER_TYPE (access_mask_t) >=LANDLOCK_NUM_ACCESS_FS ); +/** * struct landlock_layer - Access rights for a given layer */
@@ -28,7 +35,7 @@ struct landlock_layer {* @access: Bitfield of allowed actions on the kernel object. They are * relative to the object type (e.g. %LANDLOCK_ACTION_FS_READ). */ -u16 access; +access_mask_t access; };/**
@@ -135,19 +142,20 @@ struct landlock_ruleset {* layers are set once and never changed for the * lifetime of the ruleset. */ -u16 fs_access_masks[]; +access_mask_t fs_access_masks[]; }; }; }; -struct landlock_ruleset *landlock_create_ruleset (const u32 fs_access_mask); +struct landlock_ruleset * +landlock_create_ruleset (const access_mask_t fs_access_mask);void landlock_put_ruleset (struct landlock_ruleset *const ruleset);void landlock_put_ruleset_deferred (struct landlock_ruleset *const ruleset);int landlock_insert_rule (struct landlock_ruleset *const ruleset,struct landlock_object *const object, -const u32 access); +const access_mask_t access);struct landlock_ruleset * landlock_merge_ruleset(struct landlock_ruleset *const parent,
Greg Kroah-Hartman
maintainerPATCH 585/667 landlock: Reduce the maximum number of layers to 16
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 75c542d6c6cc48720376862d5496d51509160dfd upstream.
The maximum number of nested Landlock domains is currently 64. Because of the following fix and to help reduce the stack size, let's reduce it to 16. This seems large enough for a lot of use cases (e.g. sandboxed init service, spawning a sandboxed SSH service, in nested sandboxed containers). Reducing the number of nested domains may also help to discover misuse of Landlock (e.g. creating a domain per rule).
Add and use a dedicated layer_mask_t typedef to fit with the number of layers. This might be useful when changing it and to keep it consistent with the maximum number of layers.
--- Documentation/userspace-api/landlock.rst | 4 ++-- security/landlock/fs.c | 17 +++++++---------- security/landlock/limits.h | 2 +- security/landlock/ruleset.h | 4 ++++ tools/testing/selftests/landlock/fs_test.c | 2 +- 5 files changed, 15 insertions(+), 14 deletions(-)
Documentation/userspace-api/landlock.rst +2 -2
@@ -267,8 +267,8 @@ restrict such paths with dedicated rules Ruleset layers -------------- -There is a limit of 64 layers of stacked rulesets. This can be an issue for a -task willing to enforce a new ruleset in complement to its 64 inherited +There is a limit of 16 layers of stacked rulesets. This can be an issue for a +task willing to enforce a new ruleset in complement to its 16 inherited rulesets. Once this limit is reached, sys_landlock_restrict_self() returns E2BIG. It is then strongly suggested to carefully build rulesets once in the life of a thread, especially for applications able to launch other applications
security/landlock/fs.c +7 -10
@@ -183,10 +183,10 @@ int landlock_append_fs_rule(struct landl/* Access-control management */ -static inline u64 unmask_layers (const struct landlock_ruleset *const domain, -const struct path *const path, -const access_mask_t access_request, -u64 layer_mask) +static inline layer_mask_t +unmask_layers (const struct landlock_ruleset *const domain, +const struct path *const path,const access_mask_t access_request, +layer_mask_t layer_mask) {const struct landlock_rule *rule;const struct inode *inode;
@@ -212,11 +212,11 @@ static inline u64 unmask_layers(const st*/ for (i =0 ; i < rule->num_layers; i++) {const struct landlock_layer *const layer = &rule->layers[i]; -const u64 layer_level =BIT_ULL (layer->level -1 ); +const layer_mask_t layer_bit =BIT_ULL (layer->level -1 );/* Checks that the layer grants access to the full request. */ if ((layer->access & access_request) == access_request) { - layer_mask &= ~layer_level; + layer_mask &= ~layer_bit;if (layer_mask ==0 )return layer_mask;
@@ -231,12 +231,9 @@ static int check_access_path(const struc {bool allowed = false;struct path walker_path; -u64 layer_mask; +layer_mask_t layer_mask;size_t i; -/* Make sure all layers can be checked. */ -BUILD_BUG_ON (BITS_PER_TYPE (layer_mask) <LANDLOCK_MAX_NUM_LAYERS ); -if (!access_request)return 0 ;if (WARN_ON_ONCE (!domain || !path))
security/landlock/limits.h +1 -1
@@ -15,7 +15,7 @@/* clang-format off */ -#define LANDLOCK_MAX_NUM_LAYERS 64 +#define LANDLOCK_MAX_NUM_LAYERS 16#define LANDLOCK_MAX_NUM_RULES U32_MAX#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_MAKE_SYM
security/landlock/ruleset.h +4 -0
@@ -23,6 +23,10 @@ typedef u16 access_mask_t;/* Makes sure all filesystem access rights can be stored. */ static_assert (BITS_PER_TYPE (access_mask_t) >=LANDLOCK_NUM_ACCESS_FS ); +typedef u16 layer_mask_t ; +/* Makes sure all layers can be checked. */ +static_assert (BITS_PER_TYPE (layer_mask_t) >=LANDLOCK_MAX_NUM_LAYERS ); +/** * struct landlock_layer - Access rights for a given layer */
tools/testing/selftests/landlock/fs_test.c +1 -1
@@ -1159,7 +1159,7 @@ TEST_F_FORK(layout1, max_layers)const int ruleset_fd =create_ruleset (_metadata,ACCESS_RW , rules);ASSERT_LE (0 , ruleset_fd); -for (i =0 ; i <64 ; i++) +for (i =0 ; i <16 ; i++)enforce_ruleset (_metadata, ruleset_fd);for (i =0 ; i <2 ; i++) {
Greg Kroah-Hartman
maintainerPATCH 586/667 landlock: Create find_rule() from unmask_layers()
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 2cd7cd6eed88b8383cfddce589afe9c0ae1d19b4 upstream.
This refactoring will be useful in a following commit.
--- security/landlock/fs.c | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-)
security/landlock/fs.c +28 -13
@@ -183,23 +183,36 @@ int landlock_append_fs_rule(struct landl/* Access-control management */ -static inline layer_mask_t -unmask_layers (const struct landlock_ruleset *const domain, -const struct path *const path,const access_mask_t access_request, -layer_mask_t layer_mask) +/* +* The lifetime of the returned rule is tied to @domain. +* +* Returns NULL if no rule is found or if @dentry is negative. +*/ +static inline const struct landlock_rule * +find_rule (const struct landlock_ruleset *const domain, +const struct dentry *const dentry) {const struct landlock_rule *rule;const struct inode *inode; -size_t i; -if (d_is_negative (path->dentry)) -/* Ignore nonexistent leafs. */ -return layer_mask; - inode =d_backing_inode (path->dentry); +/* Ignores nonexistent leafs. */ +if (d_is_negative (dentry)) +return NULL ; + + inode =d_backing_inode (dentry);rcu_read_lock (); rule =landlock_find_rule ( domain,rcu_dereference (landlock_inode (inode)->object));rcu_read_unlock (); +return rule; +} + +static inline layer_mask_t unmask_layers (const struct landlock_rule *const rule, +const access_mask_t access_request, +layer_mask_t layer_mask) +{ +size_t layer_level; +if (!rule)return layer_mask;
@@ -210,8 +223,9 @@ unmask_layers(const struct landlock_rule* the remaining layers for each inode, from the first added layer to * the last one. */ -for (i =0 ; i < rule->num_layers; i++) { -const struct landlock_layer *const layer = &rule->layers[i]; +for (layer_level =0 ; layer_level < rule->num_layers; layer_level++) { +const struct landlock_layer *const layer = + &rule->layers[layer_level];const layer_mask_t layer_bit =BIT_ULL (layer->level -1 );/* Checks that the layer grants access to the full request. */
@@ -269,8 +283,9 @@ static int check_access_path(const strucwhile (true) {struct dentry *parent_dentry; - layer_mask =unmask_layers (domain, &walker_path, access_request, - layer_mask); + layer_mask = +unmask_layers (find_rule (domain, walker_path.dentry), + access_request, layer_mask);if (layer_mask ==0 ) {/* Stops when a rule from each layer grants access. */ allowed = true;
Greg Kroah-Hartman
maintainerPATCH 587/667 landlock: Fix same-layer rule unions
In reply to Greg Kroah-HartmanFrom: Mickaël Salaün <[email protected]>
commit 8ba0005ff418ec356e176b26eaa04a6ac755d05b upstream.
The original behavior was to check if the full set of requested accesses was allowed by at least a rule of every relevant layer. This didn't take into account requests for multiple accesses and same-layer rules allowing the union of these accesses in a complementary way. As a result, multiple accesses requested on a file hierarchy matching rules that, together, allowed these accesses, but without a unique rule allowing all of them, was illegitimately denied. This case should be rare in practice and it can only be triggered by the path_rename or file_open hook implementations.
For instance, if, for the same layer, a rule allows execution beneath /a/b and another rule allows read beneath /a, requesting access to read and execute at the same time for /a/b should be allowed for this layer.
This was an inconsistency because the union of same-layer rule accesses was already allowed if requested once at a time anyway.
This fix changes the way allowed accesses are gathered over a path walk. To take into account all these rule accesses, we store in a matrix all layer granting the set of requested accesses, according to the handled accesses. To avoid heap allocation, we use an array on the stack which is 2*13 bytes. A following commit bringing the LANDLOCK_ACCESS_FS_REFER access right will increase this size to reach 112 bytes (2*14*4) in case of link or rename actions.
Add a new layout1.layer_rule_unions test to check that accesses from different rules pertaining to the same layer are ORed in a file hierarchy. Also test that it is not the case for rules from different layers.
--- security/landlock/fs.c | 80 ++++++++++++++------- security/landlock/ruleset.h | 2 tools/testing/selftests/landlock/fs_test.c | 107 +++++++++++++++++++++++++++++ 3 files changed, 162 insertions(+), 27 deletions(-)
security/landlock/fs.c +53 -27
@@ -207,45 +207,67 @@ find_rule(const struct landlock_rulesetreturn rule; } -static inline layer_mask_t unmask_layers (const struct landlock_rule *const rule, -const access_mask_t access_request, -layer_mask_t layer_mask) +/* +* @layer_masks is read and may be updated according to the access request and +* the matching rule. +* +* Returns true if the request is allowed (i.e. relevant layer masks for the +* request are empty). +*/ +static inline bool +unmask_layers (const struct landlock_rule *const rule, +const access_mask_t access_request, +layer_mask_t (*const layer_masks)[LANDLOCK_NUM_ACCESS_FS ]) {size_t layer_level; +if (!access_request || !layer_masks) +return true;if (!rule) -return layer_mask; +return false;/* * An access is granted if, for each policy layer, at least one rule -* encountered on the pathwalk grants the requested accesses, -* regardless of their position in the layer stack. We must then check +* encountered on the pathwalk grants the requested access, +* regardless of its position in the layer stack. We must then check * the remaining layers for each inode, from the first added layer to -* the last one. +* the last one. When there is multiple requested accesses, for each +* policy layer, the full set of requested accesses may not be granted +* by only one rule, but by the union (binary OR) of multiple rules. +* E.g. /a/b <execute> + /a <read> => /a/b <execute + read> */ for (layer_level =0 ; layer_level < rule->num_layers; layer_level++) {const struct landlock_layer *const layer = &rule->layers[layer_level];const layer_mask_t layer_bit =BIT_ULL (layer->level -1 ); - -/* Checks that the layer grants access to the full request. */ -if ((layer->access & access_request) == access_request) { - layer_mask &= ~layer_bit; - -if (layer_mask ==0 ) -return layer_mask; +const unsigned long access_req = access_request; +unsigned long access_bit; +bool is_empty; + +/* +* Records in @layer_masks which layer grants access to each +* requested access. +*/ + is_empty = true; +for_each_set_bit (access_bit, &access_req, +ARRAY_SIZE (*layer_masks)) { +if (layer->access &BIT_ULL (access_bit)) + (*layer_masks)[access_bit] &= ~layer_bit; + is_empty = is_empty && !(*layer_masks)[access_bit]; } +if (is_empty) +return true; } -return layer_mask; +return false; }static int check_access_path (const struct landlock_ruleset *const domain,const struct path *const path,const access_mask_t access_request) { -bool allowed = false; +layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS ] = {}; +bool allowed = false, has_access = false;struct path walker_path; -layer_mask_t layer_mask;size_t i;if (!access_request)
@@ -265,13 +287,20 @@ static int check_access_path(const strucreturn -EACCES ;/* Saves all layers handling a subset of requested accesses. */ - layer_mask =0 ;for (i =0 ; i < domain->num_layers; i++) { -if (domain->fs_access_masks[i] & access_request) - layer_mask |=BIT_ULL (i); +const unsigned long access_req = access_request; +unsigned long access_bit; + +for_each_set_bit (access_bit, &access_req, +ARRAY_SIZE (layer_masks)) { +if (domain->fs_access_masks[i] &BIT_ULL (access_bit)) { + layer_masks[access_bit] |=BIT_ULL (i); + has_access = true; + } + } }/* An access request not handled by the domain is allowed. */ -if (layer_mask ==0 ) +if (!has_access)return 0 ; walker_path = *path;
@@ -283,14 +312,11 @@ static int check_access_path(const strucwhile (true) {struct dentry *parent_dentry; - layer_mask = -unmask_layers (find_rule (domain, walker_path.dentry), - access_request, layer_mask); -if (layer_mask ==0 ) { + allowed =unmask_layers (find_rule (domain, walker_path.dentry), + access_request, &layer_masks); +if (allowed)/* Stops when a rule from each layer grants access. */ - allowed = true;break ; - } jump_up:if (walker_path.dentry == walker_path.mnt->mnt_root) {
security/landlock/ruleset.h +2 -0
@@ -22,6 +22,8 @@typedef u16 access_mask_t ;/* Makes sure all filesystem access rights can be stored. */ static_assert (BITS_PER_TYPE (access_mask_t) >=LANDLOCK_NUM_ACCESS_FS ); +/* Makes sure for_each_set_bit() and for_each_clear_bit() calls are OK. */ +static_assert (sizeof (unsigned long ) >=sizeof (access_mask_t));typedef u16 layer_mask_t ;/* Makes sure all layers can be checked. */
tools/testing/selftests/landlock/fs_test.c +107 -0
113 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 588/667 drm/amdgpu/cs: make commands with 0 chunks illegal behaviour.
In reply to Greg Kroah-HartmanFrom: Dave Airlie <[email protected]>
commit 31ab27b14daaa75541a415c6794d6f3567fea44a upstream.
Submitting a cs with 0 chunks, causes an oops later, found trying to execute the wrong userspace driver.
MESA_LOADER_DRIVER_OVERRIDE=v3d glxinfo
[172536.665184] BUG: kernel NULL pointer dereference, address: 00000000000001d8 [172536.665188] #PF: supervisor read access in kernel mode [172536.665189] #PF: error_code(0x0000) - not-present page [172536.665191] PGD 6712a0067 P4D 6712a0067 PUD 5af9ff067 PMD 0 [172536.665195] Oops: 0000 [#1] SMP NOPTI [172536.665197] CPU: 7 PID: 2769838 Comm: glxinfo Tainted: P O 5.10.81 #1-NixOS [172536.665199] Hardware name: To be filled by O.E.M. To be filled by O.E.M./CROSSHAIR V FORMULA-Z, BIOS 2201 03/23/2015 [172536.665272] RIP: 0010:amdgpu_cs_ioctl+0x96/0x1ce0 [amdgpu] [172536.665274] Code: 75 18 00 00 4c 8b b2 88 00 00 00 8b 46 08 48 89 54 24 68 49 89 f7 4c 89 5c 24 60 31 d2 4c 89 74 24 30 85 c0 0f 85 c0 01 00 00 <48> 83 ba d8 01 00 00 00 48 8b b4 24 90 00 00 00 74 16 48 8b 46 10 [172536.665276] RSP: 0018:ffffb47c0e81bbe0 EFLAGS: 00010246 [172536.665277] RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000 [172536.665278] RDX: 0000000000000000 RSI: ffffb47c0e81be28 RDI: ffffb47c0e81bd68 [172536.665279] RBP: ffff936524080010 R08: 0000000000000000 R09: ffffb47c0e81be38 [172536.665281] R10: ffff936524080010 R11: ffff936524080000 R12: ffffb47c0e81bc40 [172536.665282] R13: ffffb47c0e81be28 R14: ffff9367bc410000 R15: ffffb47c0e81be28 [172536.665283] FS: 00007fe35e05d740(0000) GS:ffff936c1edc0000(0000) knlGS:0000000000000000 [172536.665284] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [172536.665286] CR2: 00000000000001d8 CR3: 0000000532e46000 CR4: 00000000000406e0 [172536.665287] Call Trace: [172536.665322] ? amdgpu_cs_find_mapping+0x110/0x110 [amdgpu] [172536.665332] drm_ioctl_kernel+0xaa/0xf0 [drm] [172536.665338] drm_ioctl+0x201/0x3b0 [drm] [172536.665369] ? amdgpu_cs_find_mapping+0x110/0x110 [amdgpu] [172536.665372] ? selinux_file_ioctl+0x135/0x230 [172536.665399] amdgpu_drm_ioctl+0x49/0x80 [amdgpu] [172536.665403] __x64_sys_ioctl+0x83/0xb0 [172536.665406] do_syscall_64+0x33/0x40 [172536.665409] entry_SYSCALL_64_after_hwframe+0x44/0xa9
--- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +1 -1
@@ -115,7 +115,7 @@ static int amdgpu_cs_parser_init(structint ret;if (cs->in.num_chunks ==0 ) -return 0 ; +return -EINVAL ; chunk_array =kvmalloc_array (cs->in.num_chunks,sizeof (uint64_t ),GFP_KERNEL );if (!chunk_array)
Greg Kroah-Hartman
maintainerPATCH 589/667 drm/nouveau/subdev/bus: Ratelimit logging for fault errors
In reply to Greg Kroah-HartmanFrom: Lyude Paul <[email protected]>
commit 9887bda0c831df0c044d6de147d002e48024fb4a upstream.
There's plenty of ways to fudge the GPU when developing on nouveau by mistake, some of which can result in nouveau seriously spamming dmesg with fault errors. This can be somewhat annoying, as it can quickly overrun the message buffer (or your terminal emulator's buffer) and get rid of actually useful feedback from the driver. While working on my new atomic only MST branch, I ran into this issue a couple of times.
So, let's fix this by adding nvkm_error_ratelimited(), and using it to ratelimit errors from faults. This should be fine for developers, since it's nearly always only the first few faults that we care about seeing. Plus, you can turn off rate limiting in the kernel if you really need to.
--- drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h | 2 ++ drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c | 14 +++++++------- drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c | 6 +++--- drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c | 6 +++--- 4 files changed, 15 insertions(+), 13 deletions(-)
drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h +2 -0
@@ -62,4 +62,6 @@ void nvkm_subdev_intr(struct nvkm_subdev #define nvkm_debug(s,f,a...) nvkm_printk((s), DEBUG, info, f, ##a) #define nvkm_trace(s,f,a...) nvkm_printk((s), TRACE, info, f, ##a) #define nvkm_spam(s,f,a...) nvkm_printk((s), SPAM, dbg, f, ##a) + +#define nvkm_error_ratelimited(s,f,a...) nvkm_printk((s), ERROR, err_ratelimited, f, ##a)#endif
drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c +7 -7
@@ -35,13 +35,13 @@ gf100_bus_intr(struct nvkm_bus *bus)u32 addr =nvkm_rd32 (device,0x009084 );u32 data =nvkm_rd32 (device,0x009088 ); -nvkm_error (subdev, -"MMIO %s of %08x FAULT at %06x [ %s%s%s]\n" , - (addr &0x00000002 ) ?"write" :"read" , data, - (addr &0x00fffffc ), - (stat &0x00000002 ) ?"!ENGINE " :"" , - (stat &0x00000004 ) ?"PRIVRING " :"" , - (stat &0x00000008 ) ?"TIMEOUT " :"" ); +nvkm_error_ratelimited (subdev, +"MMIO %s of %08x FAULT at %06x [ %s%s%s]\n" , + (addr &0x00000002 ) ?"write" :"read" , data, + (addr &0x00fffffc ), + (stat &0x00000002 ) ?"!ENGINE " :"" , + (stat &0x00000004 ) ?"PRIVRING " :"" , + (stat &0x00000008 ) ?"TIMEOUT " :"" );nvkm_wr32 (device,0x009084 ,0x00000000 );nvkm_wr32 (device,0x001100 , (stat &0x0000000e ));
drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c +3 -3
@@ -45,9 +45,9 @@ nv31_bus_intr(struct nvkm_bus *bus)u32 addr =nvkm_rd32 (device,0x009084 );u32 data =nvkm_rd32 (device,0x009088 ); -nvkm_error (subdev,"MMIO %s of %08x FAULT at %06x\n" , - (addr &0x00000002 ) ?"write" :"read" , data, - (addr &0x00fffffc )); +nvkm_error_ratelimited (subdev,"MMIO %s of %08x FAULT at %06x\n" , + (addr &0x00000002 ) ?"write" :"read" , data, + (addr &0x00fffffc )); stat &= ~0x00000008 ;nvkm_wr32 (device,0x001100 ,0x00000008 );
drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c +3 -3
@@ -60,9 +60,9 @@ nv50_bus_intr(struct nvkm_bus *bus)u32 addr =nvkm_rd32 (device,0x009084 );u32 data =nvkm_rd32 (device,0x009088 ); -nvkm_error (subdev,"MMIO %s of %08x FAULT at %06x\n" , - (addr &0x00000002 ) ?"write" :"read" , data, - (addr &0x00fffffc )); +nvkm_error_ratelimited (subdev,"MMIO %s of %08x FAULT at %06x\n" , + (addr &0x00000002 ) ?"write" :"read" , data, + (addr &0x00fffffc )); stat &= ~0x00000008 ;nvkm_wr32 (device,0x001100 ,0x00000008 );
Greg Kroah-Hartman
maintainerPATCH 590/667 drm/etnaviv: check for reaped mapping in etnaviv_iommu_unmap_gem
In reply to Greg Kroah-HartmanFrom: Lucas Stach <[email protected]>
commit e168c25526cd0368af098095c2ded4a008007e1b upstream.
When the mapping is already reaped the unmap must be a no-op, as we would otherwise try to remove the mapping twice, corrupting the involved data structures.
--- drivers/gpu/drm/etnaviv/etnaviv_mmu.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/gpu/drm/etnaviv/etnaviv_mmu.c +6 -0
@@ -286,6 +286,12 @@ void etnaviv_iommu_unmap_gem(struct etnamutex_lock (&context->lock); +/* Bail if the mapping has been reaped by another thread */ +if (!mapping->context) { +mutex_unlock (&context->lock); +return ; + } +/* If the vram node is on the mm, unmap and remove the node */ if (mapping->vram_node.mm == &context->mm)etnaviv_iommu_remove_mapping (context, mapping);
Greg Kroah-Hartman
maintainerPATCH 591/667 drm/nouveau/clk: Fix an incorrect NULL check on list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 1c3b2a27def609473ed13b1cd668cb10deab49b4 upstream.
The bug is here:
if (nvkm_cstate_valid(clk, cstate, max_volt, clk->temp)) return cstate;
The list iterator value 'cstate' will *always* be set and non-NULL by list_for_each_entry_from_reverse(), so it is incorrect to assume that the iterator value will be unchanged if the list is empty or no element is found (In fact, it will be a bogus pointer to an invalid structure object containing the HEAD). Also it missed a NULL check at callsite and may lead to invalid memory access after that.
To fix this bug, just return 'encoder' when found, otherwise return NULL. And add the NULL check.
--- drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +4 -2
@@ -135,10 +135,10 @@ nvkm_cstate_find_best(struct nvkm_clk *clist_for_each_entry_from_reverse (cstate, &pstate->list, head) {if (nvkm_cstate_valid (clk, cstate, max_volt, clk->temp)) -break ; +return cstate; } -return cstate; +return NULL ; } static struct nvkm_cstate *
@@ -169,6 +169,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, sif (!list_empty (&pstate->list)) { cstate =nvkm_cstate_get (clk, pstate, cstatei); cstate =nvkm_cstate_find_best (clk, pstate, cstate); +if (!cstate) +return -EINVAL ; }else { cstate = &pstate->base; }
Greg Kroah-Hartman
maintainerPATCH 592/667 drm/nouveau/kms/nv50-: atom: fix an incorrect NULL check on list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 6ce4431c7ba7954c4fa6a96ce16ca1b2943e1a83 upstream.
The bug is here:
return encoder;
The list iterator value 'encoder' will *always* be set and non-NULL by drm_for_each_encoder_mask(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element found. Otherwise it will bypass some NULL checks and lead to invalid memory access passing the check.
To fix this bug, just return 'encoder' when found, otherwise return NULL.
--- drivers/gpu/drm/nouveau/dispnv50/atom.h | 6 +++--- drivers/gpu/drm/nouveau/dispnv50/crc.c | 27 ++++++++++++++++++++++----- 2 files changed, 25 insertions(+), 8 deletions(-)
drivers/gpu/drm/nouveau/dispnv50/atom.h +3 -3
@@ -160,14 +160,14 @@ nv50_head_atom_get(struct drm_atomic_stastatic inline struct drm_encoder *nv50_head_atom_get_encoder (struct nv50_head_atom *atom) { -struct drm_encoder *encoder =NULL ; +struct drm_encoder *encoder;/* We only ever have a single encoder */ drm_for_each_encoder_mask (encoder, atom->state.crtc->dev, atom->state.encoder_mask) -break ; +return encoder; -return encoder; +return NULL ; }#define nv50_wndw_atom (p) container_of((p), struct nv50_wndw_atom, state)
drivers/gpu/drm/nouveau/dispnv50/crc.c +22 -5
@@ -411,9 +411,18 @@ void nv50_crc_atomic_check_outp(struct nstruct nv50_head_atom *armh =nv50_head_atom (old_crtc_state);struct nv50_head_atom *asyh =nv50_head_atom (new_crtc_state);struct nv50_outp_atom *outp_atom; -struct nouveau_encoder *outp = -nv50_real_outp (nv50_head_atom_get_encoder (armh)); -struct drm_encoder *encoder = &outp->base.base; +struct nouveau_encoder *outp; +struct drm_encoder *encoder, *enc; + + enc =nv50_head_atom_get_encoder (armh); +if (!enc) +continue ; + + outp =nv50_real_outp (enc); +if (!outp) +continue ; + + encoder = &outp->base.base;if (!asyh->clr.crc)continue ;
@@ -464,8 +473,16 @@ void nv50_crc_atomic_set(struct nv50_heastruct drm_device *dev = crtc->dev;struct nv50_crc *crc = &head->crc;const struct nv50_crc_func *func =nv50_disp (dev)->core->func->crc; -struct nouveau_encoder *outp = -nv50_real_outp (nv50_head_atom_get_encoder (asyh)); +struct nouveau_encoder *outp; +struct drm_encoder *encoder; + + encoder =nv50_head_atom_get_encoder (asyh); +if (!encoder) +return ; + + outp =nv50_real_outp (encoder); +if (!outp) +return ; func->set_src(head, outp->or, nv50_crc_source_type(outp, asyh->crc.src),
Greg Kroah-Hartman
maintainerPATCH 593/667 drm/bridge: analogix_dp: Grab runtime PM reference for DP-AUX
In reply to Greg Kroah-HartmanFrom: Brian Norris <[email protected]>
commit 8fb6c44fe8468f92ac7b8bbfcca4404a4e88645f upstream.
If the display is not enable()d, then we aren't holding a runtime PM reference here. Thus, it's easy to accidentally cause a hang, if user space is poking around at /dev/drm_dp_aux0 at the "wrong" time.
Let's get a runtime PM reference, and check that we "see" the panel. Don't force any panel power-up, etc., because that can be intrusive, and that's not what other drivers do (see drivers/gpu/drm/bridge/ti-sn65dsi86.c and drivers/gpu/drm/bridge/parade-ps8640.c.)
--- drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c +12 -1
@@ -1632,8 +1632,19 @@ static ssize_t analogix_dpaux_transfer(s struct drm_dp_aux_msg *msg) {struct analogix_dp_device *dp =to_dp (aux); +int ret; -return analogix_dp_transfer (dp, msg); +pm_runtime_get_sync (dp->dev); + + ret =analogix_dp_detect_hpd (dp); +if (ret) + goto out; + + ret =analogix_dp_transfer (dp, msg); +out: +pm_runtime_put (dp->dev); + +return ret; } struct analogix_dp_device *
Greg Kroah-Hartman
maintainerPATCH 594/667 drm/i915/dsi: fix VBT send packet port selection for ICL+
In reply to Greg Kroah-HartmanFrom: Jani Nikula <[email protected]>
commit 0ea917819d12fed41ea4662cc26ffa0060a5c354 upstream.
The VBT send packet port selection was never updated for ICL+ where the 2nd link is on port B instead of port C as in VLV+ DSI.
First, single link DSI needs to use the configured port instead of relying on the VBT sequence block port. Remove the hard-coded port C check here and make it generic. For reference, see commit f915084edc5a ("drm/i915: Changes related to the sequence port no for") for the original VLV specific fix.
Second, the sequence block port number is either 0 or 1, where 1 indicates the 2nd link. Remove the hard-coded port C here for 2nd link. (This could be a "find second set bit" on DSI ports, but just check the two possible options.)
Third, sanity check the result with a warning to avoid a NULL pointer dereference.
--- drivers/gpu/drm/i915/display/intel_dsi_vbt.c | 33 ++++++++++++++++++--------- 1 file changed, 22 insertions(+), 11 deletions(-)
drivers/gpu/drm/i915/display/intel_dsi_vbt.c +22 -11
@@ -121,9 +121,25 @@ struct i2c_adapter_lookup {#define ICL_GPIO_DDPA_CTRLCLK_2 8#define ICL_GPIO_DDPA_CTRLDATA_2 9 -static enum port intel_dsi_seq_port_to_port (u8 port) +static enum port intel_dsi_seq_port_to_port (struct intel_dsi *intel_dsi, +u8 seq_port) { -return port ?PORT_C :PORT_A ; +/* +* If single link DSI is being used on any port, the VBT sequence block +* send packet apparently always has 0 for the port. Just use the port +* we have configured, and ignore the sequence block port. +*/ +if (hweight8 (intel_dsi->ports) ==1 ) +return ffs (intel_dsi->ports) -1 ; + +if (seq_port) { +if (intel_dsi->ports &PORT_B ) +return PORT_B ; +else if (intel_dsi->ports &PORT_C ) +return PORT_C ; + } + +return PORT_A ; } static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi,
@@ -145,15 +161,10 @@ static const u8 *mipi_exec_send_packet(s seq_port = (flags >>MIPI_PORT_SHIFT ) &3 ; -/* For DSI single link on Port A & C, the seq_port value which is -* parsed from Sequence Block#53 of VBT has been set to 0 -* Now, read/write of packets for the DSI single link on Port A and -* Port C will based on the DVO port from VBT block 2. -*/ -if (intel_dsi->ports == (1 <<PORT_C )) - port =PORT_C ; -else - port =intel_dsi_seq_port_to_port (seq_port); + port =intel_dsi_seq_port_to_port (intel_dsi, seq_port); + +if (drm_WARN_ON (&dev_priv->drm, !intel_dsi->dsi_hosts[port])) + goto out; dsi_device = intel_dsi->dsi_hosts[port]->device;if (!dsi_device) {
Greg Kroah-Hartman
maintainerPATCH 595/667 md: fix an incorrect NULL check in does_sb_need_changing
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit fc8738343eefc4ea8afb6122826dea48eacde514 upstream.
The bug is here:
if (!rdev)
The list iterator value 'rdev' will *always* be set and non-NULL by rdev_for_each(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element found. Otherwise it will bypass the NULL check and lead to invalid memory access passing the check.
To fix the bug, use a new variable 'iter' as the list iterator, while using the original variable 'rdev' as a dedicated pointer to point to the found element.
--- drivers/md/md.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/md/md.c +5 -3
@@ -2628,14 +2628,16 @@ static void sync_sbs(struct mddev *mddevstatic bool does_sb_need_changing (struct mddev *mddev) { -struct md_rdev *rdev; +struct md_rdev *rdev =NULL , *iter;struct mdp_superblock_1 *sb;int role;/* Find a good rdev */ -rdev_for_each (rdev, mddev) -if ((rdev->raid_disk >=0 ) && !test_bit (Faulty, &rdev->flags)) +rdev_for_each (iter, mddev) +if ((iter->raid_disk >=0 ) && !test_bit (Faulty, &iter->flags)) { + rdev = iter;break ; + }/* No good device found. */ if (!rdev)
Greg Kroah-Hartman
maintainerPATCH 596/667 md: fix an incorrect NULL check in md_reload_sb
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 64c54d9244a4efe9bc6e9c98e13c4bbb8bb39083 upstream.
The bug is here:
if (!rdev || rdev->desc_nr != nr) {The list iterator value 'rdev' will *always* be set and non-NULL by rdev_for_each_rcu(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element found (In fact, it will be a bogus pointer to an invalid struct object containing the HEAD). Otherwise it will bypass the check and lead to invalid memory access passing the check.
To fix the bug, use a new variable 'iter' as the list iterator, while using the original variable 'pdev' as a dedicated pointer to point to the found element.
--- drivers/md/md.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
drivers/md/md.c +6 -4
@@ -9774,16 +9774,18 @@ static int read_rdev(struct mddev *mddevvoid md_reload_sb (struct mddev *mddev,int nr) { -struct md_rdev *rdev; +struct md_rdev *rdev =NULL , *iter;int err;/* Find the rdev */ -rdev_for_each_rcu (rdev, mddev) { -if (rdev->desc_nr == nr) +rdev_for_each_rcu (iter, mddev) { +if (iter->desc_nr == nr) { + rdev = iter;break ; + } } -if (!rdev || rdev->desc_nr != nr) { +if (!rdev) {pr_warn ("%s: %d Could not find rdev with nr %d\n" , __func__, __LINE__, nr);return ; }
Greg Kroah-Hartman
maintainerPATCH 597/667 mtd: cfi_cmdset_0002: Move and rename chip_check/chip_ready/chip_good_for_write
In reply to Greg Kroah-HartmanFrom: Tokunori Ikegami <[email protected]>
commit 083084df578a8bdb18334f69e7b32d690aaa3247 upstream.
This is a preparation patch for the S29GL064N buffer writes fix. There is no functional change.
--- drivers/mtd/chips/cfi_cmdset_0002.c | 95 ++++++++++++------------------------ 1 file changed, 32 insertions(+), 63 deletions(-)
drivers/mtd/chips/cfi_cmdset_0002.c +32 -63
@@ -802,21 +802,25 @@ static struct mtd_info *cfi_amdstd_setup }/* -* Return true if the chip is ready. +* Return true if the chip is ready and has the correct value. * * Ready is one of: read mode, query mode, erase-suspend-read mode (in any * non-suspended sector) and is indicated by no toggle bits toggling. * +* Error are indicated by toggling bits or bits held with the wrong value, +* or with bits toggling. +* * Note that anything more complicated than checking if no bits are toggling * (including checking DQ5 for an error status) is tricky to get working * correctly and is therefore not done (particularly with interleaved chips * as each chip must be checked independently of the others). */ static int __xipram chip_ready(struct map_info *map, struct flchip *chip, -unsigned long addr) +unsigned long addr,map_word *expected) {struct cfi_private *cfi = map->fldrv_priv;map_word d, t; +int ret;if (cfi_use_status_reg (cfi)) {map_word ready =CMD (CFI_SR_DRB );
@@ -826,57 +830,20 @@ static int __xipram chip_ready(struct ma*/ cfi_send_gen_cmd (0x70 , cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type,NULL ); - d =map_read (map, addr); + t =map_read (map, addr); -return map_word_andequal (map, d, ready, ready); +return map_word_andequal (map, t, ready, ready); } d =map_read (map, addr); t =map_read (map, addr); -return map_word_equal (map, d, t); -} - -/* -* Return true if the chip is ready and has the correct value. -* -* Ready is one of: read mode, query mode, erase-suspend-read mode (in any -* non-suspended sector) and it is indicated by no bits toggling. -* -* Error are indicated by toggling bits or bits held with the wrong value, -* or with bits toggling. -* -* Note that anything more complicated than checking if no bits are toggling -* (including checking DQ5 for an error status) is tricky to get working -* correctly and is therefore not done (particularly with interleaved chips -* as each chip must be checked independently of the others). -* -*/ -static int __xipram chip_good(struct map_info *map, struct flchip *chip, -unsigned long addr,map_word expected) -{ -struct cfi_private *cfi = map->fldrv_priv; -map_word oldd, curd; - -if (cfi_use_status_reg (cfi)) { -map_word ready =CMD (CFI_SR_DRB ); - -/* -* For chips that support status register, check device -* ready bit -*/ -cfi_send_gen_cmd (0x70 , cfi->addr_unlock1, chip->start, map, cfi, - cfi->device_type,NULL ); - curd =map_read (map, addr); - -return map_word_andequal (map, curd, ready, ready); - } + ret =map_word_equal (map, d, t); - oldd =map_read (map, addr); - curd =map_read (map, addr); +if (!ret || !expected) +return ret; -return map_word_equal (map, oldd, curd) && -map_word_equal (map, curd, expected); +return map_word_equal (map, t, *expected); }static int get_chip (struct map_info *map,struct flchip *chip,unsigned long adr,int mode)
@@ -893,7 +860,7 @@ static int get_chip(struct map_info *mapcase FL_STATUS :for (;;) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))break ;if (time_after (jiffies, timeo)) {
@@ -932,7 +899,7 @@ static int get_chip(struct map_info *map chip->state =FL_ERASE_SUSPENDING ; chip->erase_suspended =1 ;for (;;) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))break ;if (time_after (jiffies, timeo)) {
@@ -1463,7 +1430,7 @@ static int do_otp_lock(struct map_info */* wait for chip to become ready */ timeo = jiffies +msecs_to_jiffies (2 );for (;;) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))break ;if (time_after (jiffies, timeo)) {
@@ -1695,11 +1662,11 @@ static int __xipram do_write_oneword_onc }/* -* We check "time_after" and "!chip_good" before checking -* "chip_good" to avoid the failure due to scheduling. +* We check "time_after" and "!chip_ready" before checking +* "chip_ready" to avoid the failure due to scheduling. */ if (time_after (jiffies, timeo) && - !chip_good (map, chip, adr, datum)) { + !chip_ready (map, chip, adr, &datum)) {xip_enable (map, chip, adr);printk (KERN_WARNING "MTD %s(): software timeout\n" , __func__);xip_disable (map, chip, adr);
@@ -1707,7 +1674,7 @@ static int __xipram do_write_oneword_oncbreak ; } -if (chip_good (map, chip, adr, datum)) { +if (chip_ready (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
@@ -1975,18 +1942,18 @@ static int __xipram do_write_buffer_wait }/* -* We check "time_after" and "!chip_good" before checking -* "chip_good" to avoid the failure due to scheduling. +* We check "time_after" and "!chip_ready" before checking +* "chip_ready" to avoid the failure due to scheduling. */ if (time_after (jiffies, timeo) && - !chip_good (map, chip, adr, datum)) { + !chip_ready (map, chip, adr, &datum)) {pr_err ("MTD %s(): software timeout, address:0x%.8lx.\n" , __func__, adr); ret = -EIO ;break ; } -if (chip_good (map, chip, adr, datum)) { +if (chip_ready (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
@@ -2195,7 +2162,7 @@ static int cfi_amdstd_panic_wait(struct* If the driver thinks the chip is idle, and no toggle bits * are changing, then the chip is actually idle for sure. */ -if (chip->state ==FL_READY &&chip_ready (map, chip, adr)) +if (chip->state ==FL_READY &&chip_ready (map, chip, adr,NULL ))return 0 ;/*
@@ -2212,7 +2179,7 @@ static int cfi_amdstd_panic_wait(struct/* wait for the chip to become ready */ for (i =0 ; i <jiffies_to_usecs (timeo); i++) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))return 0 ;udelay (1 );
@@ -2276,13 +2243,13 @@ retry:map_write (map, datum, adr);for (i =0 ; i <jiffies_to_usecs (uWriteTimeout); i++) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))break ;udelay (1 ); } -if (!chip_good (map, chip, adr, datum) || +if (!chip_ready (map, chip, adr, &datum) ||cfi_check_err_status (map, chip, adr)) {/* reset on all failures. */ map_write (map,CMD (0xF0 ), chip->start);
@@ -2424,6 +2391,7 @@ static int __xipram do_erase_chip(structDECLARE_WAITQUEUE (wait, current);int ret;int retry_cnt =0 ; +map_word datum =map_word_ff (map); adr = cfi->addr_unlock1;
@@ -2478,7 +2446,7 @@ static int __xipram do_erase_chip(struct chip->erase_suspended =0 ; } -if (chip_good (map, chip, adr,map_word_ff (map))) { +if (chip_ready (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
@@ -2523,6 +2491,7 @@ static int __xipram do_erase_oneblock(stDECLARE_WAITQUEUE (wait, current);int ret;int retry_cnt =0 ; +map_word datum =map_word_ff (map); adr += chip->start;
@@ -2577,7 +2546,7 @@ static int __xipram do_erase_oneblock(st chip->erase_suspended =0 ; } -if (chip_good (map, chip, adr,map_word_ff (map))) { +if (chip_ready (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
@@ -2771,7 +2740,7 @@ static int __maybe_unused do_ppb_xxlock(*/ timeo = jiffies +msecs_to_jiffies (2000 );/* 2s max (un)locking */ for (;;) { -if (chip_ready (map, chip, adr)) +if (chip_ready (map, chip, adr,NULL ))break ;if (time_after (jiffies, timeo)) {
Greg Kroah-Hartman
maintainerPATCH 598/667 mtd: cfi_cmdset_0002: Use chip_ready() for write on S29GL064N
In reply to Greg Kroah-HartmanFrom: Tokunori Ikegami <[email protected]>
commit 0a8e98305f63deaf0a799d5cf5532cc83af035d1 upstream.
Since commit dfeae1073583("mtd: cfi_cmdset_0002: Change write buffer to check correct value") buffered writes fail on S29GL064N. This is because, on S29GL064N, reads return 0xFF at the end of DQ polling for write completion, where as, chip_good() check expects actual data written to the last location to be returned post DQ polling completion. Fix is to revert to using chip_good() for S29GL064N which only checks for DQ lines to settle down to determine write completion.
--- drivers/mtd/chips/cfi_cmdset_0002.c | 42 +++++++++++++++++++++++++++++------- include/linux/mtd/cfi.h | 1 2 files changed, 35 insertions(+), 8 deletions(-)
drivers/mtd/chips/cfi_cmdset_0002.c +34 -8
@@ -59,6 +59,10 @@#define CFI_SR_WBASB BIT(3)#define CFI_SR_SLSB BIT(1) +enum cfi_quirks { +CFI_QUIRK_DQ_TRUE_DATA =BIT (0 ), +}; +static int cfi_amdstd_read (struct mtd_info *,loff_t ,size_t ,size_t *,u_char *);static int cfi_amdstd_write_words (struct mtd_info *,loff_t ,size_t ,size_t *,const u_char *);#if !FORCE_WORD_WRITE
@@ -436,6 +440,15 @@ static void fixup_s29ns512p_sectors(stru mtd->name); } +static void fixup_quirks (struct mtd_info *mtd) +{ +struct map_info *map = mtd->priv; +struct cfi_private *cfi = map->fldrv_priv; + +if (cfi->mfr ==CFI_MFR_AMD && cfi->id ==0x0c01 ) + cfi->quirks |=CFI_QUIRK_DQ_TRUE_DATA ; +} +/* Used to fix CFI-Tables of chips without Extended Query Tables */ static struct cfi_fixup cfi_nopri_fixup_table[] = { {CFI_MFR_SST ,0x234a , fixup_sst39vf },/* SST39VF1602 */
@@ -474,6 +487,7 @@ static struct cfi_fixup cfi_fixup_table[ #if !FORCE_WORD_WRITE { CFI_MFR_ANY, CFI_ID_ANY, fixup_use_write_buffers }, #endif + { CFI_MFR_ANY, CFI_ID_ANY, fixup_quirks }, { 0, 0, NULL } }; static struct cfi_fixup jedec_fixup_table[] = {
@@ -846,6 +860,18 @@ static int __xipram chip_ready(struct mareturn map_word_equal (map, t, *expected); } +static int __xipram chip_good(struct map_info *map, struct flchip *chip, +unsigned long addr,map_word *expected) +{ +struct cfi_private *cfi = map->fldrv_priv; +map_word *datum = expected; + +if (cfi->quirks &CFI_QUIRK_DQ_TRUE_DATA ) + datum =NULL ; + +return chip_ready (map, chip, addr, datum); +} +static int get_chip (struct map_info *map,struct flchip *chip,unsigned long adr,int mode) {DECLARE_WAITQUEUE (wait, current);
@@ -1662,11 +1688,11 @@ static int __xipram do_write_oneword_onc }/* -* We check "time_after" and "!chip_ready" before checking -* "chip_ready" to avoid the failure due to scheduling. +* We check "time_after" and "!chip_good" before checking +* "chip_good" to avoid the failure due to scheduling. */ if (time_after (jiffies, timeo) && - !chip_ready (map, chip, adr, &datum)) { + !chip_good (map, chip, adr, &datum)) {xip_enable (map, chip, adr);printk (KERN_WARNING "MTD %s(): software timeout\n" , __func__);xip_disable (map, chip, adr);
@@ -1674,7 +1700,7 @@ static int __xipram do_write_oneword_oncbreak ; } -if (chip_ready (map, chip, adr, &datum)) { +if (chip_good (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
@@ -1942,18 +1968,18 @@ static int __xipram do_write_buffer_wait }/* -* We check "time_after" and "!chip_ready" before checking -* "chip_ready" to avoid the failure due to scheduling. +* We check "time_after" and "!chip_good" before checking +* "chip_good" to avoid the failure due to scheduling. */ if (time_after (jiffies, timeo) && - !chip_ready (map, chip, adr, &datum)) { + !chip_good (map, chip, adr, &datum)) {pr_err ("MTD %s(): software timeout, address:0x%.8lx.\n" , __func__, adr); ret = -EIO ;break ; } -if (chip_ready (map, chip, adr, &datum)) { +if (chip_good (map, chip, adr, &datum)) {if (cfi_check_err_status (map, chip, adr)) ret = -EIO ;break ;
include/linux/mtd/cfi.h +1 -0
@@ -286,6 +286,7 @@ struct cfi_private {map_word sector_erase_cmd;unsigned long chipshift;/* Because they're of the same type */ const char *im_name;/* inter_module name for cmdset_setup */ +unsigned long quirks;struct flchip chips[];/* per-chip data structure for each chip */ };
Greg Kroah-Hartman
maintainerPATCH 599/667 media: coda: Fix reported H264 profile
In reply to Greg Kroah-HartmanFrom: Nicolas Dufresne <[email protected]>
commit 7110c08ea71953a7fc342f0b76046f72442cf26c upstream.
The CODA960 manual states that ASO/FMO features of baseline are not supported, so for this reason this driver should only report constrained baseline support.
This fixes negotiation issue with constrained baseline content on GStreamer 1.17.1.
ASO/FMO features are unsupported for the encoder and untested for the decoder because there is currently no userspace support. Neither GStreamer parsers nor FFMPEG parsers support ASO/FMO.
--- drivers/media/platform/coda/coda-common.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/media/platform/coda/coda-common.c +3 -3
@@ -2346,8 +2346,8 @@ static void coda_encode_ctrls(struct cod V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, -12, 12, 1, 0);v4l2_ctrl_new_std_menu (&ctx->ctrls, &coda_ctrl_ops,V4L2_CID_MPEG_VIDEO_H264_PROFILE , -V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE ,0x0 , -V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE ); +V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE ,0x0 , +V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE );if (ctx->dev->devtype->product ==CODA_HX4 || ctx->dev->devtype->product ==CODA_7541 ) { v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
@@ -2428,7 +2428,7 @@ static void coda_decode_ctrls(struct cod ctx->h264_profile_ctrl =v4l2_ctrl_new_std_menu (&ctx->ctrls, &coda_ctrl_ops,V4L2_CID_MPEG_VIDEO_H264_PROFILE ,V4L2_MPEG_VIDEO_H264_PROFILE_HIGH , - ~((1 <<V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE ) | + ~((1 <<V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE ) | (1 <<V4L2_MPEG_VIDEO_H264_PROFILE_MAIN ) | (1 <<V4L2_MPEG_VIDEO_H264_PROFILE_HIGH )),V4L2_MPEG_VIDEO_H264_PROFILE_HIGH );
Greg Kroah-Hartman
maintainerPATCH 600/667 media: coda: Add more H264 levels for CODA960
In reply to Greg Kroah-HartmanFrom: Nicolas Dufresne <[email protected]>
commit eb2fd187abc878a2dfad46902becb74963473c7d upstream.
Add H264 level 1.0, 4.1, 4.2 to the list of supported formats. While the hardware does not fully support these levels, it does support most of them. The constraints on frame size and pixel formats already cover the limitation.
This fixes negotiation of level on GStreamer 1.17.1.
--- drivers/media/platform/coda/coda-common.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
drivers/media/platform/coda/coda-common.c +6 -3
@@ -2361,12 +2361,15 @@ static void coda_encode_ctrls(struct codif (ctx->dev->devtype->product ==CODA_960 ) {v4l2_ctrl_new_std_menu (&ctx->ctrls, &coda_ctrl_ops,V4L2_CID_MPEG_VIDEO_H264_LEVEL , -V4L2_MPEG_VIDEO_H264_LEVEL_4_0 , - ~((1 <<V4L2_MPEG_VIDEO_H264_LEVEL_2_0 ) | +V4L2_MPEG_VIDEO_H264_LEVEL_4_2 , + ~((1 <<V4L2_MPEG_VIDEO_H264_LEVEL_1_0 ) | + (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_2_0 ) | (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_3_0 ) | (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_3_1 ) | (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_3_2 ) | - (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_4_0 )), + (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_4_0 ) | + (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_4_1 ) | + (1 <<V4L2_MPEG_VIDEO_H264_LEVEL_4_2 )),V4L2_MPEG_VIDEO_H264_LEVEL_4_0 ); } v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
Greg Kroah-Hartman
maintainerPATCH 601/667 ima: remove the IMA_TEMPLATE Kconfig option
In reply to Greg Kroah-HartmanFrom: GUO Zihua <[email protected]>
commit 891163adf180bc369b2f11c9dfce6d2758d2a5bd upstream.
The original 'ima' measurement list template contains a hash, defined as 20 bytes, and a null terminated pathname, limited to 255 characters. Other measurement list templates permit both larger hashes and longer pathnames. When the "ima" template is configured as the default, a new measurement list template (ima_template=) must be specified before specifying a larger hash algorithm (ima_hash=) on the boot command line.
To avoid this boot command line ordering issue, remove the legacy "ima" template configuration option, allowing it to still be specified on the boot command line.
The root cause of this issue is that during the processing of ima_hash, we would try to check whether the hash algorithm is compatible with the template. If the template is not set at the moment we do the check, we check the algorithm against the configured default template. If the default template is "ima", then we reject any hash algorithm other than sha1 and md5.
For example, if the compiled default template is "ima", and the default algorithm is sha1 (which is the current default). In the cmdline, we put in "ima_hash=sha256 ima_template=ima-ng". The expected behavior would be that ima starts with ima-ng as the template and sha256 as the hash algorithm. However, during the processing of "ima_hash=", "ima_template=" has not been processed yet, and hash_setup would check the configured hash algorithm against the compiled default: ima, and reject sha256. So at the end, the hash algorithm that is actually used will be sha1.
With template "ima" removed from the configured default, we ensure that the default tempalte would at least be "ima-ng" which allows for basically any hash algorithm.
This change would not break the algorithm compatibility checks for IMA.
--- security/integrity/ima/Kconfig | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
security/integrity/ima/Kconfig +6 -8
@@ -69,10 +69,9 @@ choice hash, defined as 20 bytes, and a null terminated pathname, limited to 255 characters. The 'ima-ng' measurement list template permits both larger hash digests and longer - pathnames. + pathnames. The configured default template can be replaced + by specifying "ima_template=" on the boot command line. - config IMA_TEMPLATE - bool "ima" config IMA_NG_TEMPLATE bool "ima-ng (default)" config IMA_SIG_TEMPLATE
@@ -82,7 +81,6 @@ endchoice config IMA_DEFAULT_TEMPLATE string depends on IMA - default "ima" if IMA_TEMPLATE default "ima-ng" if IMA_NG_TEMPLATE default "ima-sig" if IMA_SIG_TEMPLATE
@@ -102,19 +100,19 @@ choice config IMA_DEFAULT_HASH_SHA256 bool "SHA256" - depends on CRYPTO_SHA256=y && !IMA_TEMPLATE + depends on CRYPTO_SHA256=y config IMA_DEFAULT_HASH_SHA512 bool "SHA512" - depends on CRYPTO_SHA512=y && !IMA_TEMPLATE + depends on CRYPTO_SHA512=y config IMA_DEFAULT_HASH_WP512 bool "WP512" - depends on CRYPTO_WP512=y && !IMA_TEMPLATE + depends on CRYPTO_WP512=y config IMA_DEFAULT_HASH_SM3 bool "SM3" - depends on CRYPTO_SM3=y && !IMA_TEMPLATE + depends on CRYPTO_SM3=y endchoice config IMA_DEFAULT_HASH
Greg Kroah-Hartman
maintainerPATCH 602/667 Kconfig: Add option for asm goto w/ tied outputs to workaround clang-13 bug
In reply to Greg Kroah-HartmanFrom: Sean Christopherson <[email protected]>
commit 1aa0e8b144b6474c4914439d232d15bfe883636b upstream.
Add a config option to guard (future) usage of asm_volatile_goto() that includes "tied outputs", i.e. "+" constraints that specify both an input and output parameter. clang-13 has a bug[1] that causes compilation of such inline asm to fail, and KVM wants to use a "+m" constraint to implement a uaccess form of CMPXCHG[2]. E.g. the test code fails with
<stdin>:1:29: error: invalid operand in inline asm: '.long (${1:l}) - .'
int foo(int *x) { asm goto (".long (%l[bar]) - .\n": "+m"(*x) ::: bar); return *x; bar: return 0; }
^
<stdin>:1:29: error: unknown token in expression
<inline asm>:1:9: note: instantiated into assembly here
.long () - .
^2 errors generated.
on clang-13, but passes on gcc (with appropriate asm goto support). The bug is fixed in clang-14, but won't be backported to clang-13 as the changes are too invasive/risky.
gcc also had a similar bug[3], fixed in gcc-11, where gcc failed to account for its behavior of assigning two numbers to tied outputs (one for input, one for output) when evaluating symbolic references.
[1] https://github.com/ClangBuiltLinux/linux/issues/1512
[2] https://lore.kernel.org/all/YfMruK8%[email protected]
[3] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98096
Message-Id: <[email protected]>
--- init/Kconfig | 5 +++++ 1 file changed, 5 insertions(+)
init/Kconfig +5 -0
@@ -77,6 +77,11 @@ config CC_HAS_ASM_GOTO_OUTPUT depends on CC_HAS_ASM_GOTO def_bool $(success,echo 'int foo(int x) { asm goto ("": "=r"(x) ::: bar); return x; bar: return 0; }' | $(CC) -x c - -c -o /dev/null) +config CC_HAS_ASM_GOTO_TIED_OUTPUT + depends on CC_HAS_ASM_GOTO_OUTPUT + # Detect buggy gcc and clang, fixed in gcc-11 clang-14. + def_bool $(success,echo 'int foo(int *x) { asm goto (".long (%l[bar]) - .\n": "+m"(*x) ::: bar); return *x; bar: return 0; }' | $CC -x c - -c -o /dev/null) + config TOOLS_SUPPORT_RELR def_bool $(success,env "CC=$(CC)" "LD=$(LD)" "NM=$(NM)" "OBJCOPY=$(OBJCOPY)" $(srctree)/scripts/tools-support-relr.sh)
Greg Kroah-Hartman
maintainerPATCH 603/667 RDMA/hfi1: Fix potential integer multiplication overflow errors
In reply to Greg Kroah-HartmanFrom: Dennis Dalessandro <[email protected]>
commit f93e91a0372c922c20d5bee260b0f43b4b8a1bee upstream.
When multiplying of different types, an overflow is possible even when storing the result in a larger type. This is because the conversion is done after the multiplication. So arithmetic overflow and thus in incorrect value is possible.
Correct an instance of this in the inter packet delay calculation. Fix by ensuring one of the operands is u64 which will promote the other to u64 as well ensuring no overflow.
--- drivers/infiniband/hw/hfi1/init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/hfi1/init.c +1 -1
@@ -488,7 +488,7 @@ void set_link_ipg(struct hfi1_pportdatau16 shift, mult;u64 src;u32 current_egress_rate;/* Mbits /sec */ -u32 max_pkt_time; +u64 max_pkt_time;/* * max_pkt_time is the maximum packet egress time in units * of the fabric clock period 1/(805 MHz).
Greg Kroah-Hartman
maintainerPATCH 604/667 mmc: core: Allows to override the timeout value for ioctl() path
In reply to Greg Kroah-HartmanFrom: Bean Huo <[email protected]>
commit 23e09be254f95a5b75cd87f91a4014f3b46dda3f upstream.
Occasionally, user-land applications initiate longer timeout values for certain commands through ioctl() system call. But so far we are still using a fixed timeout of 10 seconds in mmc_poll_for_busy() on the ioctl() path, even if a custom timeout is specified in the userspace application. This patch allows custom timeout values to override this default timeout values on the ioctl path.
--- drivers/mmc/core/block.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/mmc/core/block.c +4 -4
@@ -609,11 +609,11 @@ static int __mmc_blk_ioctl_cmd(struct mmif (idata->rpmb || (cmd.flags &MMC_RSP_R1B ) ==MMC_RSP_R1B ) {/* -* Ensure RPMB/R1B command has completed by polling CMD13 -* "Send Status". +* Ensure RPMB/R1B command has completed by polling CMD13 "Send Status". Here we +* allow to override the default timeout value if a custom timeout is specified. */ - err =mmc_poll_for_busy (card,MMC_BLK_TIMEOUT_MS , false, -MMC_BUSY_IO ); + err =mmc_poll_for_busy (card, idata->ic.cmd_timeout_ms ? :MMC_BLK_TIMEOUT_MS , + false,MMC_BUSY_IO ); }return err;
Greg Kroah-Hartman
maintainerPATCH 605/667 csky: patch_text: Fixup last cpu should be master
In reply to Greg Kroah-HartmanFrom: Guo Ren <[email protected]>
commit 8c4d16471e2babe9bdfe41d6ef724526629696cb upstream.
These patch_text implementations are using stop_machine_cpuslocked infrastructure with atomic cpu_count. The original idea: When the master CPU patch_text, the others should wait for it. But current implementation is using the first CPU as master, which couldn't guarantee the remaining CPUs are waiting. This patch changes the last CPU as the master to solve the potential risk.
--- arch/csky/kernel/probes/kprobes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/csky/kernel/probes/kprobes.c +1 -1
@@ -28,7 +28,7 @@ static int __kprobes patch_text_cb(voidstruct csky_insn_patch *param = priv;unsigned int addr = (unsigned int )param->addr; -if (atomic_inc_return (¶m->cpu_count) ==1 ) { +if (atomic_inc_return (¶m->cpu_count) ==num_online_cpus ()) { *(u16 *) addr =cpu_to_le16 (param->opcode);dcache_wb_range (addr, addr +2 );atomic_inc (¶m->cpu_count);
Greg Kroah-Hartman
maintainerPATCH 606/667 irqchip/armada-370-xp: Do not touch Performance Counter Overflow on A375, A38x, A39x
In reply to Greg Kroah-HartmanFrom: Pali Rohár <[email protected]>
commit a3d66a76348daf559873f19afc912a2a7c2ccdaf upstream.
Register ARMADA_370_XP_INT_FABRIC_MASK_OFFS is Armada 370 and XP specific and on new Armada platforms it has different meaning. It does not configure Performance Counter Overflow interrupt masking. So do not touch this register on non-A370/XP platforms (A375, A38x and A39x).
--- drivers/irqchip/irq-armada-370-xp.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
drivers/irqchip/irq-armada-370-xp.c +10 -1
@@ -308,7 +308,16 @@ static inline int armada_370_xp_msi_initstatic void armada_xp_mpic_perf_init (void ) { -unsigned long cpuid =cpu_logical_map (smp_processor_id ()); +unsigned long cpuid; + +/* +* This Performance Counter Overflow interrupt is specific for +* Armada 370 and XP. It is not available on Armada 375, 38x and 39x. +*/ +if (!of_machine_is_compatible ("marvell,armada-370-xp" )) +return ; + + cpuid =cpu_logical_map (smp_processor_id ());/* Enable Performance Counter Overflow interrupts */ writel(ARMADA_370_XP_INT_CAUSE_PERF(cpuid),
Greg Kroah-Hartman
maintainerPATCH 607/667 irqchip: irq-xtensa-mx: fix initial IRQ affinity
In reply to Greg Kroah-HartmanFrom: Max Filippov <[email protected]>
commit a255ee29252066d621df5d6b420bf534c6ba5bc0 upstream.
When irq-xtensa-mx chip is used in non-SMP configuration its irq_set_affinity callback is not called leaving IRQ affinity set empty. As a result IRQ delivery does not work in that configuration. Initialize IRQ affinity of the xtensa MX interrupt distributor to CPU 0 for all external IRQ lines.
--- drivers/irqchip/irq-xtensa-mx.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
drivers/irqchip/irq-xtensa-mx.c +14 -4
@@ -151,14 +151,25 @@ static struct irq_chip xtensa_mx_irq_chi .irq_set_affinity = xtensa_mx_irq_set_affinity, }; +static void __init xtensa_mx_init_common (struct irq_domain *root_domain) +{ +unsigned int i; + +irq_set_default_host (root_domain); +secondary_init_irq (); + +/* Initialize default IRQ routing to CPU 0 */ +for (i =0 ; i <XCHAL_NUM_EXTINTERRUPTS ; ++i) +set_er (1 ,MIROUT (i)); +} +int __init xtensa_mx_init_legacy (struct device_node *interrupt_parent) {struct irq_domain *root_domain =irq_domain_add_legacy (NULL ,NR_IRQS -1 ,1 ,0 , &xtensa_mx_irq_domain_ops, &xtensa_mx_irq_chip); -irq_set_default_host (root_domain); -secondary_init_irq (); +xtensa_mx_init_common (root_domain);return 0 ; }
@@ -168,8 +179,7 @@ static int __init xtensa_mx_init(structstruct irq_domain *root_domain =irq_domain_add_linear (np,NR_IRQS , &xtensa_mx_irq_domain_ops, &xtensa_mx_irq_chip); -irq_set_default_host (root_domain); -secondary_init_irq (); +xtensa_mx_init_common (root_domain);return 0 ; }IRQCHIP_DECLARE (xtensa_mx_irq_chip,"cdns,xtensa-mx" , xtensa_mx_init);
Greg Kroah-Hartman
maintainerPATCH 608/667 thermal: devfreq_cooling: use local ops instead of global ops
In reply to Greg Kroah-HartmanFrom: Kant Fan <[email protected]>
commit b947769b8f778db130aad834257fcaca25df2edc upstream.
Fix access illegal address problem in following condition:
There are multiple devfreq cooling devices in system, some of them has EM model but others do not. Energy model ops such as state2power will append to global devfreq_cooling_ops when the cooling device with EM model is registered. It makes the cooling device without EM model also use devfreq_cooling_ops after appending when registered later by of_devfreq_cooling_register_power() or of_devfreq_cooling_register().
The IPA governor regards the cooling devices without EM model as a power actor, because they also have energy model ops, and will access illegal address at dfc->em_pd when execute cdev->ops->get_requested_power, cdev->ops->state2power or cdev->ops->power2state.
--- drivers/thermal/devfreq_cooling.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-)
drivers/thermal/devfreq_cooling.c +18 -7
@@ -358,21 +358,28 @@ of_devfreq_cooling_register_power(structstruct thermal_cooling_device *cdev;struct device *dev = df->dev.parent;struct devfreq_cooling_device *dfc; +struct thermal_cooling_device_ops *ops;char *name;int err, num_opps; - dfc =kzalloc (sizeof (*dfc),GFP_KERNEL ); -if (!dfc) + ops =kmemdup (&devfreq_cooling_ops,sizeof (*ops),GFP_KERNEL ); +if (!ops)return ERR_PTR (-ENOMEM ); + dfc =kzalloc (sizeof (*dfc),GFP_KERNEL ); +if (!dfc) { + err = -ENOMEM ; + goto free_ops; + } + dfc->devfreq = df; dfc->em_pd =em_pd_get (dev);if (dfc->em_pd) { - devfreq_cooling_ops.get_requested_power = + ops->get_requested_power = devfreq_cooling_get_requested_power; - devfreq_cooling_ops.state2power = devfreq_cooling_state2power; - devfreq_cooling_ops.power2state = devfreq_cooling_power2state; + ops->state2power = devfreq_cooling_state2power; + ops->power2state = devfreq_cooling_power2state; dfc->power_ops = dfc_power;
@@ -407,8 +414,7 @@ of_devfreq_cooling_register_power(structif (!name) goto remove_qos_req; - cdev =thermal_of_cooling_device_register (np, name, dfc, - &devfreq_cooling_ops); + cdev =thermal_of_cooling_device_register (np, name, dfc, ops);kfree (name);if (IS_ERR (cdev)) {
@@ -429,6 +435,8 @@ free_table:kfree (dfc->freq_table); free_dfc:kfree (dfc); +free_ops: +kfree (ops);return ERR_PTR (err); }
@@ -510,11 +518,13 @@ EXPORT_SYMBOL_GPL(devfreq_cooling_em_regvoid devfreq_cooling_unregister (struct thermal_cooling_device *cdev) {struct devfreq_cooling_device *dfc; +const struct thermal_cooling_device_ops *ops;struct device *dev;if (IS_ERR_OR_NULL (cdev))return ; + ops = cdev->ops; dfc = cdev->devdata; dev = dfc->devfreq->dev.parent;
@@ -525,5 +535,6 @@ void devfreq_cooling_unregister(struct tkfree (dfc->freq_table);kfree (dfc); +kfree (ops); }EXPORT_SYMBOL_GPL (devfreq_cooling_unregister);
Greg Kroah-Hartman
maintainerPATCH 609/667 cfg80211: declare MODULE_FIRMWARE for regulatory.db
In reply to Greg Kroah-HartmanFrom: Dimitri John Ledkov <[email protected]>
commit 7bc7981eeebe1b8e603ad2ffc5e84f4df76920dd upstream.
Add MODULE_FIRMWARE declarations for regulatory.db and regulatory.db.p7s such that userspace tooling can discover and include these files.
--- net/wireless/reg.c | 4 ++++ 1 file changed, 4 insertions(+)
net/wireless/reg.c +4 -0
@@ -806,6 +806,8 @@ static int __init load_builtin_regdb_keyreturn 0 ; } +MODULE_FIRMWARE ("regulatory.db.p7s" ); +static bool regdb_has_valid_signature (const u8 *data,unsigned int size) {const struct firmware *sig;
@@ -1077,6 +1079,8 @@ static void regdb_fw_cb(const struct firrelease_firmware (fw); } +MODULE_FIRMWARE ("regulatory.db" ); +static int query_regdb_file (const char *alpha2) {ASSERT_RTNL ();
Greg Kroah-Hartman
maintainerPATCH 610/667 mac80211: upgrade passive scan to active scan on DFS channels after beacon rx
In reply to Greg Kroah-HartmanFrom: Felix Fietkau <[email protected]>
commit b041b7b9de6e1d4362de855ab90f9d03ef323edd upstream.
In client mode, we can't connect to hidden SSID APs or SSIDs not advertised in beacons on DFS channels, since we're forced to passive scan. Fix this by sending out a probe request immediately after the first beacon, if active scan was requested by the user.
--- net/mac80211/ieee80211_i.h | 5 +++++ net/mac80211/scan.c | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+)
net/mac80211/ieee80211_i.h +5 -0
@@ -1129,6 +1129,9 @@ struct tpt_led_trigger {* a scan complete for an aborted scan. * @SCAN_HW_CANCELLED: Set for our scan work function when the scan is being * cancelled. +* @SCAN_BEACON_WAIT: Set whenever we're passive scanning because of radar/no-IR +* and could send a probe request after receiving a beacon. +* @SCAN_BEACON_DONE: Beacon received, we can now send a probe request */ enum {SCAN_SW_SCANNING ,
@@ -1137,6 +1140,8 @@ enum {SCAN_COMPLETED ,SCAN_ABORTED ,SCAN_HW_CANCELLED , +SCAN_BEACON_WAIT , + SCAN_BEACON_DONE, };/**
net/mac80211/scan.c +20 -0
@@ -277,6 +277,16 @@ void ieee80211_scan_rx(struct ieee80211_if (likely (!sdata1 && !sdata2))return ; +if (test_and_clear_bit (SCAN_BEACON_WAIT , &local->scanning)) { +/* +* we were passive scanning because of radar/no-IR, but +* the beacon/proberesp rx gives us an opportunity to upgrade +* to active scan +*/ +set_bit (SCAN_BEACON_DONE , &local->scanning); +ieee80211_queue_delayed_work (&local->hw, &local->scan_work,0 ); + } +if (ieee80211_is_probe_resp (mgmt->frame_control)) {struct cfg80211_scan_request *scan_req;struct cfg80211_sched_scan_request *sched_scan_req;
@@ -783,6 +793,8 @@ static int __ieee80211_start_scan(struct IEEE80211_CHAN_RADAR)) || !req->n_ssids) { next_delay = IEEE80211_PASSIVE_CHANNEL_TIME; + if (req->n_ssids) + set_bit(SCAN_BEACON_WAIT, &local->scanning); } else {ieee80211_scan_state_send_probe (local, &next_delay); next_delay =IEEE80211_CHANNEL_TIME ;
@@ -994,6 +1006,8 @@ set_channel: !scan_req->n_ssids) { *next_delay =IEEE80211_PASSIVE_CHANNEL_TIME ; local->next_scan_state =SCAN_DECISION ; +if (scan_req->n_ssids) +set_bit (SCAN_BEACON_WAIT , &local->scanning);return ; }
@@ -1086,6 +1100,8 @@ void ieee80211_scan_work(struct work_str goto out; } +clear_bit (SCAN_BEACON_WAIT , &local->scanning); +/* * as long as no delay is required advance immediately * without scheduling a new work
@@ -1096,6 +1112,10 @@ void ieee80211_scan_work(struct work_str goto out_complete; } +if (test_and_clear_bit (SCAN_BEACON_DONE , &local->scanning) && + local->next_scan_state ==SCAN_DECISION ) + local->next_scan_state =SCAN_SEND_PROBE ; +switch (local->next_scan_state) {case SCAN_DECISION :/* if no more bands/channels left, complete scan */
Greg Kroah-Hartman
maintainerPATCH 611/667 um: Use asm-generic/dma-mapping.h
In reply to Greg Kroah-HartmanFrom: Johannes Berg <[email protected]>
commit 365719035526e8eda214a1cedb2e1c96e969a0d7 upstream.
If DMA (PCI over virtio) is enabled, then some drivers may enable CONFIG_DMA_OPS as well, and then we pull in the x86 definition of get_arch_dma_ops(), which uses the dma_ops symbol, which isn't defined.
Since we don't have real DMA ops nor any kind of IOMMU fix this in the simplest possible way: pull in the asm-generic file instead of inheriting the x86 one. It's not clear why those drivers that do (e.g. VDPA) "select DMA_OPS", and if they'd even work with this, but chances are nobody will be wanting to do that anyway, so fixing the build failure is good enough.
--- arch/um/include/asm/Kbuild | 1 + 1 file changed, 1 insertion(+)
arch/um/include/asm/Kbuild +1 -0
@@ -4,6 +4,7 @@ generic-y += bug.h generic-y += compat.h generic-y += current.h generic-y += device.h +generic-y += dma-mapping.h generic-y += emergency-restart.h generic-y += exec.h generic-y += extable.h
Signature · 1 line
2.36.1
Greg Kroah-Hartman
maintainerPATCH 612/667 um: chan_user: Fix winch_tramp() return value
In reply to Greg Kroah-HartmanFrom: Johannes Berg <[email protected]>
commit 57ae0b67b747031bc41fb44643aa5344ab58607e upstream.
The previous fix here was only partially correct, it did result in returning a proper error value in case of error, but it also clobbered the pid that we need to return from this function (not just zero for success).
As a result, it returned 0 here, but later this is treated as a pid and used to kill the process, but since it's now 0 we kill(0, SIGKILL), which makes UML kill itself rather than just the helper thread.
Fix that and make it more obvious by using a separate variable for the pid.
--- arch/um/drivers/chan_user.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
arch/um/drivers/chan_user.c +5 -4
@@ -220,7 +220,7 @@ static int winch_tramp(int fd, struct tt unsigned long *stack_out) {struct winch_data data; -int fds[2 ], n, err; +int fds[2 ], n, err, pid;char c; err =os_pipe (fds,1 ,1 );
@@ -238,8 +238,9 @@ static int winch_tramp(int fd, struct tt* problem with /dev/net/tun, which if held open by this * thread, prevents the TUN/TAP device from being reused. */ - err =run_helper_thread (winch_thread, &data,CLONE_FILES , stack_out); -if (err <0 ) { + pid =run_helper_thread (winch_thread, &data,CLONE_FILES , stack_out); +if (pid <0 ) { + err = pid;printk (UM_KERN_ERR "fork of winch_thread failed - errno = %d\n" , -err); goto out_close;
@@ -263,7 +264,7 @@ static int winch_tramp(int fd, struct tt goto out_close; } -return err; +return pid; out_close:close (fds[1 ]);
Greg Kroah-Hartman
maintainerPATCH 613/667 um: Fix out-of-bounds read in LDT setup
In reply to Greg Kroah-HartmanFrom: Vincent Whitchurch <[email protected]>
commit 2a4a62a14be1947fa945c5c11ebf67326381a568 upstream.
syscall_stub_data() expects the data_count parameter to be the number of longs, not bytes.
==================================================================
BUG: KASAN: stack-out-of-bounds in syscall_stub_data+0x70/0xe0 Read of size 128 at addr 000000006411f6f0 by task swapper/1 CPU: 0 PID: 1 Comm: swapper Not tainted 5.18.0+ #18 Call Trace: show_stack.cold+0x166/0x2a7 __dump_stack+0x3a/0x43 dump_stack_lvl+0x1f/0x27 print_report.cold+0xdb/0xf81 kasan_report+0x119/0x1f0 kasan_check_range+0x3a3/0x440 memcpy+0x52/0x140 syscall_stub_data+0x70/0xe0 write_ldt_entry+0xac/0x190 init_new_ldt+0x515/0x960 init_new_context+0x2c4/0x4d0 mm_init.constprop.0+0x5ed/0x760 mm_alloc+0x118/0x170 0x60033f48 do_one_initcall+0x1d7/0x860 0x60003e7b kernel_init+0x6e/0x3d4 new_thread_handler+0x1e7/0x2c0 The buggy address belongs to stack of task swapper/1 and is located at offset 64 in frame: init_new_ldt+0x0/0x960
This frame has 2 objects:
[32, 40) 'addr'
[64, 80) 'desc'
==================================================================
--- arch/x86/um/ldt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
arch/x86/um/ldt.c +4 -2
@@ -23,9 +23,11 @@ static long write_ldt_entry(struct mm_id {long res;void *stub_addr; + +BUILD_BUG_ON (sizeof (*desc) %sizeof (long )); + res =syscall_stub_data (mm_idp, (unsigned long *)desc, - (sizeof (*desc) +sizeof (long ) -1 ) & - ~(sizeof (long ) -1 ), +sizeof (*desc) /sizeof (long ), addr, &stub_addr);if (!res) { unsigned long args[] = { func,
Greg Kroah-Hartman
maintainerPATCH 614/667 kexec_file: drop weak attribute from arch_kexec_apply_relocations[_add]
In reply to Greg Kroah-HartmanFrom: Naveen N. Rao <[email protected]>
commit 3e35142ef99fe6b4fe5d834ad43ee13cca10a2dc upstream.
Since commit d1bcae833b32f1 ("ELF: Don't generate unused section symbols") [1], binutils (v2.36+) started dropping section symbols that it thought were unused. This isn't an issue in general, but with kexec_file.c, gcc is placing kexec_arch_apply_relocations[_add] into a separate .text.unlikely section and the section symbol ".text.unlikely" is being dropped. Due to this, recordmcount is unable to find a non-weak symbol in .text.unlikely to generate a relocation record against.
Address this by dropping the weak attribute from these functions. Instead, follow the existing pattern of having architectures #define the name of the function they want to override in their headers.
[1] https://sourceware.org/git/?p=binutils-gdb.git;a=commit;h=d1bcae833b32f1
--- arch/s390/include/asm/kexec.h | 10 +++++++++ arch/x86/include/asm/kexec.h | 8 +++++++ include/linux/kexec.h | 46 ++++++++++++++++++++++++++++++++++-------- kernel/kexec_file.c | 34 ------------------------------- 4 files changed, 56 insertions(+), 42 deletions(-)
arch/s390/include/asm/kexec.h +10 -0
@@ -9,6 +9,8 @@#ifndef _S390_KEXEC_H#define _S390_KEXEC_H +#include <linux/module.h> +#include <asm/processor.h> #include <asm/page.h> #include <asm/setup.h>
@@ -83,4 +85,12 @@ struct kimage_arch {extern const struct kexec_file_ops s390_kexec_image_ops;extern const struct kexec_file_ops s390_kexec_elf_ops; +#ifdef CONFIG_KEXEC_FILE +struct purgatory_info ; +int arch_kexec_apply_relocations_add (struct purgatory_info *pi, +Elf_Shdr *section, +const Elf_Shdr *relsec, +const Elf_Shdr *symtab); +#define arch_kexec_apply_relocations_add arch_kexec_apply_relocations_add +#endif #endif /*_S390_KEXEC_H */
arch/x86/include/asm/kexec.h +8 -0
@@ -186,6 +186,14 @@ extern int arch_kexec_post_alloc_pages(vextern void arch_kexec_pre_free_pages (void *vaddr,unsigned int pages);#define arch_kexec_pre_free_pages arch_kexec_pre_free_pages +#ifdef CONFIG_KEXEC_FILE +struct purgatory_info ; +int arch_kexec_apply_relocations_add (struct purgatory_info *pi, +Elf_Shdr *section, +const Elf_Shdr *relsec, +const Elf_Shdr *symtab); +#define arch_kexec_apply_relocations_add arch_kexec_apply_relocations_add +#endif #endif typedef void crash_vmclear_fn (void );
include/linux/kexec.h +38 -8
58 lines not on this page · raw message
kernel/kexec_file.c +0 -34
@@ -109,40 +109,6 @@ int __weak arch_kexec_kernel_verify_sig(#endif /* -* arch_kexec_apply_relocations_add - apply relocations of type RELA -* @pi: Purgatory to be relocated. -* @section: Section relocations applying to. -* @relsec: Section containing RELAs. -* @symtab: Corresponding symtab. -* -* Return: 0 on success, negative errno on error. -*/ -int __weak -arch_kexec_apply_relocations_add (struct purgatory_info *pi,Elf_Shdr *section, -const Elf_Shdr *relsec,const Elf_Shdr *symtab) -{ -pr_err ("RELA relocation unsupported.\n" ); -return -ENOEXEC ; -} - -/* -* arch_kexec_apply_relocations - apply relocations of type REL -* @pi: Purgatory to be relocated. -* @section: Section relocations applying to. -* @relsec: Section containing RELs. -* @symtab: Corresponding symtab. -* -* Return: 0 on success, negative errno on error. -*/ -int __weak -arch_kexec_apply_relocations (struct purgatory_info *pi,Elf_Shdr *section, -const Elf_Shdr *relsec,const Elf_Shdr *symtab) -{ -pr_err ("REL relocation unsupported.\n" ); -return -ENOEXEC ; -} - -/* * Free up memory used by kernel, initrd, and command line. This is temporary * memory allocation which is not needed any more after these buffers have * been loaded into separate segments and have been copied elsewhere.
Greg Kroah-Hartman
maintainerPATCH 615/667 ftrace: Clean up hash direct_functions on register failures
In reply to Greg Kroah-HartmanFrom: Song Liu <[email protected]>
commit 7d54c15cb89a29a5f59e5ffc9ee62e6591769ef1 upstream.
We see the following GPF when register_ftrace_direct fails:
[ ] general protection fault, probably for non-canonical address \
0x200000000000010: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC PTI
[...]
[ ] RIP: 0010:ftrace_find_rec_direct+0x53/0x70
[ ] Code: 48 c1 e0 03 48 03 42 08 48 8b 10 31 c0 48 85 d2 74 [...] [ ] RSP: 0018:ffffc9000138bc10 EFLAGS: 00010206
[ ] RAX: 0000000000000000 RBX: ffffffff813e0df0 RCX: 000000000000003b [ ] RDX: 0200000000000000 RSI: 000000000000000c RDI: ffffffff813e0df0 [ ] RBP: ffffffffa00a3000 R08: ffffffff81180ce0 R09: 0000000000000001 [ ] R10: ffffc9000138bc18 R11: 0000000000000001 R12: ffffffff813e0df0 [ ] R13: ffffffff813e0df0 R14: ffff888171b56400 R15: 0000000000000000 [ ] FS: 00007fa9420c7780(0000) GS:ffff888ff6a00000(0000) knlGS:000000000 [ ] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ ] CR2: 000000000770d000 CR3: 0000000107d50003 CR4: 0000000000370ee0 [ ] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ ] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ ] Call Trace:
[ ] <TASK> [ ] register_ftrace_direct+0x54/0x290 [ ] ? render_sigset_t+0xa0/0xa0 [ ] bpf_trampoline_update+0x3f5/0x4a0 [ ] ? 0xffffffffa00a3000 [ ] bpf_trampoline_link_prog+0xa9/0x140 [ ] bpf_tracing_prog_attach+0x1dc/0x450 [ ] bpf_raw_tracepoint_open+0x9a/0x1e0 [ ] ? find_held_lock+0x2d/0x90 [ ] ? lock_release+0x150/0x430 [ ] __sys_bpf+0xbd6/0x2700 [ ] ? lock_is_held_type+0xd8/0x130 [ ] __x64_sys_bpf+0x1c/0x20 [ ] do_syscall_64+0x3a/0x80 [ ] entry_SYSCALL_64_after_hwframe+0x44/0xae
[ ] RIP: 0033:0x7fa9421defa9
[ ] Code: 00 c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 9 f8 [...] [ ] RSP: 002b:00007ffed743bd78 EFLAGS: 00000246 ORIG_RAX: 0000000000000141 [ ] RAX: ffffffffffffffda RBX: 00000000069d2480 RCX: 00007fa9421defa9 [ ] RDX: 0000000000000078 RSI: 00007ffed743bd80 RDI: 0000000000000011 [ ] RBP: 00007ffed743be00 R08: 0000000000bb7270 R09: 0000000000000000 [ ] R10: 00000000069da210 R11: 0000000000000246 R12: 0000000000000001 [ ] R13: 00007ffed743c4b0 R14: 00000000069d2480 R15: 0000000000000001 [ ] </TASK>
[ ] Modules linked in: klp_vm(OK)
[ ] ---[ end trace 0000000000000000 ]---
One way to trigger this is:
1. load a livepatch that patches kernel function xxx;
2. run bpftrace -e 'kfunc:xxx {}', this will fail (expected for now);
3. repeat #2 => gpf.
This is because the entry is added to direct_functions, but not removed. Fix this by remove the entry from direct_functions when register_ftrace_direct fails.
Also remove the last trailing space from ftrace.c, so we don't have to worry about it anymore.
--- kernel/trace/ftrace.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
kernel/trace/ftrace.c +2 -3
@@ -4420,7 +4420,7 @@ int ftrace_func_mapper_add_ip(struct ftr* @ip: The instruction pointer address to remove the data from * * Returns the data if it is found, otherwise NULL. -* Note, if the data pointer is used as the data itself, (see +* Note, if the data pointer is used as the data itself, (see * ftrace_func_mapper_find_ip(), then the return value may be meaningless, * if the data pointer was set to zero. */
@@ -5146,8 +5146,6 @@ int register_ftrace_direct(unsigned long__add_hash_entry (direct_functions, entry); ret =ftrace_set_filter_ip (&direct_ops, ip,0 ,0 ); -if (ret) -remove_hash_entry (direct_functions, entry);if (!ret && !(direct_ops.flags &FTRACE_OPS_FL_ENABLED )) { ret =register_ftrace_function (&direct_ops);
@@ -5156,6 +5154,7 @@ int register_ftrace_direct(unsigned long }if (ret) { +remove_hash_entry (direct_functions, entry);kfree (entry);if (!direct->count) {list_del_rcu (&direct->next);
Greg Kroah-Hartman
maintainerPATCH 616/667 ksmbd: fix outstanding credits related bugs
In reply to Greg Kroah-HartmanFrom: Hyunchul Lee <[email protected]>
commit 376b9133826865568167b4091ef92a68c4622b87 upstream.
outstanding credits must be initialized to 0,
because it means the sum of credits consumed by
in-flight requests.
And outstanding credits must be compared with
total credits in smb2_validate_credit_charge(),
because total credits are the sum of credits
granted by ksmbd.
This patch fix the following error,
while frametest with Windows clients:
Limits exceeding the maximum allowable outstanding requests, given : 128, pending : 8065
--- fs/ksmbd/connection.c | 2 +- fs/ksmbd/smb2misc.c | 2 +- fs/ksmbd/smb_common.c | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-)
fs/ksmbd/connection.c +1 -1
@@ -62,7 +62,7 @@ struct ksmbd_conn *ksmbd_conn_alloc(voidatomic_set (&conn->req_running,0 );atomic_set (&conn->r_count,0 ); conn->total_credits =1 ; - conn->outstanding_credits =1 ; + conn->outstanding_credits =0 ;init_waitqueue_head (&conn->req_running_q);INIT_LIST_HEAD (&conn->conns_list);
fs/ksmbd/smb2misc.c +1 -1
@@ -339,7 +339,7 @@ static int smb2_validate_credit_charge(s ret =1 ; } -if ((u64 )conn->outstanding_credits + credit_charge > conn->vals->max_credits) { +if ((u64 )conn->outstanding_credits + credit_charge > conn->total_credits) {ksmbd_debug (SMB ,"Limits exceeding the maximum allowable outstanding requests, given : %u, pending : %u\n" , credit_charge, conn->outstanding_credits); ret =1 ;
fs/ksmbd/smb_common.c +3 -1
@@ -140,8 +140,10 @@ int ksmbd_verify_smb_message(struct ksmb hdr = work->request_buf;if (*(__le32 *)hdr->Protocol ==SMB1_PROTO_NUMBER && - hdr->Command ==SMB_COM_NEGOTIATE ) + hdr->Command ==SMB_COM_NEGOTIATE ) { + work->conn->outstanding_credits++;return 0 ; + }return -EINVAL ; }
Greg Kroah-Hartman
maintainerPATCH 617/667 iommu/msm: Fix an incorrect NULL check on list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 8b9ad480bd1dd25f4ff4854af5685fa334a2f57a upstream.
The bug is here:
if (!iommu || iommu->dev->of_node != spec->np) {The list iterator value 'iommu' will *always* be set and non-NULL by list_for_each_entry(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element is found (in fact, it will point to a invalid structure object containing HEAD).
To fix the bug, use a new value 'iter' as the list iterator, while use the old value 'iommu' as a dedicated variable to point to the found one, and remove the unneeded check for 'iommu->dev->of_node != spec->np' outside the loop.
--- drivers/iommu/msm_iommu.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/iommu/msm_iommu.c +7 -4
@@ -615,16 +615,19 @@ static void insert_iommu_master(struct dstatic int qcom_iommu_of_xlate (struct device *dev,struct of_phandle_args *spec) { -struct msm_iommu_dev *iommu; +struct msm_iommu_dev *iommu =NULL , *iter;unsigned long flags;int ret =0 ;spin_lock_irqsave (&msm_iommu_lock, flags); -list_for_each_entry (iommu, &qcom_iommu_devices, dev_node) -if (iommu->dev->of_node == spec->np) +list_for_each_entry (iter, &qcom_iommu_devices, dev_node) { +if (iter->dev->of_node == spec->np) { + iommu = iter;break ; + } + } -if (!iommu || iommu->dev->of_node != spec->np) { +if (!iommu) { ret = -ENODEV ; goto fail; }
Greg Kroah-Hartman
maintainerPATCH 618/667 iommu/dma: Fix iova map result check bug
In reply to Greg Kroah-HartmanFrom: Yunfei Wang <[email protected]>
commit a3884774d731f03d3a3dd4fb70ec2d9341ceb39d upstream.
The data type of the return value of the iommu_map_sg_atomic is ssize_t, but the data type of iova size is size_t, e.g. one is int while the other is unsigned int.
When iommu_map_sg_atomic return value is compared with iova size, it will force the signed int to be converted to unsigned int, if iova map fails and iommu_map_sg_atomic return error code is less than 0, then (ret < iova_len) is false, which will to cause not do free iova, and the master can still successfully get the iova of map fail, which is not expected.
Therefore, we need to check the return value of iommu_map_sg_atomic in two cases according to whether it is less than 0.
--- drivers/iommu/dma-iommu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/iommu/dma-iommu.c +4 -3
@@ -619,6 +619,7 @@ static struct page **__iommu_dma_alloc_nunsigned int count, min_size, alloc_sizes = domain->pgsize_bitmap;struct page **pages;dma_addr_t iova; +ssize_t ret;if (static_branch_unlikely (&iommu_deferred_attach_enabled) &&iommu_deferred_attach (dev, domain))
@@ -656,8 +657,8 @@ static struct page **__iommu_dma_alloc_narch_dma_prep_coherent (sg_page (sg), sg->length); } -if (iommu_map_sg_atomic (domain, iova, sgt->sgl, sgt->orig_nents, ioprot) - < size) + ret =iommu_map_sg_atomic (domain, iova, sgt->sgl, sgt->orig_nents, ioprot); +if (ret <0 || ret < size) goto out_free_sg; sgt->sgl->dma_address = iova;
@@ -1054,7 +1055,7 @@ static int iommu_dma_map_sg(struct devic* implementation - it knows better than we do. */ ret =iommu_map_sg_atomic (domain, iova, sg, nents, prot); -if (ret < iova_len) +if (ret <0 || ret < iova_len) goto out_free_iova;return __finalise_sg (dev, sg, nents, iova);
Greg Kroah-Hartman
maintainerPATCH 619/667 Revert "mm/cma.c: remove redundant cma_mutex lock"
In reply to Greg Kroah-HartmanFrom: Dong Aisheng <[email protected]>
commit 60a60e32cf91169840abcb4a80f0b0df31708ba7 upstream.
This reverts commit a4efc174b382fcdb which introduced a regression issue that when there're multiple processes allocating dma memory in parallel by calling dma_alloc_coherent(), it may fail sometimes as follows:
Error log:
cma: cma_alloc: linux,cma: alloc failed, req-size: 148 pages, ret: -16
cma: number of available pages:
3@125+20@172+12@236+4@380+32@736+17@2287+23@2473+20@36076+99@40477+108@40852+44@41108+20@41196+108@41364+108@41620+ 108@42900+108@43156+483@44061+1763@45341+1440@47712+20@49324+20@49388+5076@49452+2304@55040+35@58141+20@58220+20@58284+ 7188@58348+84@66220+7276@66452+227@74525+6371@75549=> 33161 free of 81920 total pages
When issue happened, we saw there were still 33161 pages (129M) free CMA memory and a lot available free slots for 148 pages in CMA bitmap that we want to allocate.
When dumping memory info, we found that there was also ~342M normal memory, but only 1352K CMA memory left in buddy system while a lot of pageblocks were isolated.
Memory info log:
Normal free:351096kB min:30000kB low:37500kB high:45000kB reserved_highatomic:0KB
active_anon:98060kB inactive_anon:98948kB active_file:60864kB inactive_file:31776kB unevictable:0kB writepending:0kB present:1048576kB managed:1018328kB mlocked:0kB bounce:0kB free_pcp:220kB local_pcp:192kB free_cma:1352kB lowmem_reserve[]: 0 0 0 Normal: 78*4kB (UECI) 1772*8kB (UMECI) 1335*16kB (UMECI) 360*32kB (UMECI) 65*64kB (UMCI) 36*128kB (UMECI) 16*256kB (UMCI) 6*512kB (EI) 8*1024kB (UEI) 4*2048kB (MI) 8*4096kB (EI) 8*8192kB (UI) 3*16384kB (EI) 8*32768kB (M) = 489288kB
The root cause of this issue is that since commit a4efc174b382 ("mm/cma.c:
remove redundant cma_mutex lock"), CMA supports concurrent memory allocation. It's possible that the memory range process A trying to alloc has already been isolated by the allocation of process B during memory migration.
The problem here is that the memory range isolated during one allocation by start_isolate_page_range() could be much bigger than the real size we want to alloc due to the range is aligned to MAX_ORDER_NR_PAGES.
Taking an ARMv7 platform with 1G memory as an example, when MAX_ORDER_NR_PAGES is big (e.g. 32M with max_order 14) and CMA memory is relatively small (e.g. 128M), there're only 4 MAX_ORDER slot, then it's very easy that all CMA memory may have already been isolated by other processes when one trying to allocate memory using dma_alloc_coherent(). Since current CMA code will only scan one time of whole available CMA memory, then dma_alloc_coherent() may easy fail due to contention with other processes.
This patch simply falls back to the original method that using cma_mutex to make alloc_contig_range() run sequentially to avoid the issue.
--- mm/cma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
mm/cma.c +3 -1
@@ -37,6 +37,7 @@struct cma cma_areas[MAX_CMA_AREAS ];unsigned cma_area_count; +static DEFINE_MUTEX (cma_mutex);phys_addr_t cma_get_base (const struct cma *cma) {
@@ -471,9 +472,10 @@ struct page *cma_alloc(struct cma *cma,spin_unlock_irq (&cma->lock); pfn = cma->base_pfn + (bitmap_no << cma->order_per_bit); +mutex_lock (&cma_mutex); ret =alloc_contig_range (pfn, pfn + count,MIGRATE_CMA ,GFP_KERNEL | (no_warn ? __GFP_NOWARN :0 )); - +mutex_unlock (&cma_mutex);if (ret ==0 ) { page =pfn_to_page (pfn);break ;
Greg Kroah-Hartman
maintainerPATCH 620/667 mm/page_alloc: always attempt to allocate at least one page during bulk allocation
In reply to Greg Kroah-HartmanFrom: Mel Gorman <[email protected]>
commit c572e4888ad1be123c1516ec577ad30a700bbec4 upstream.
Peter Pavlisko reported the following problem on kernel bugzilla 216007.
When I try to extract an uncompressed tar archive (2.6 milion files, 760.3 GiB in size) on newly created (empty) XFS file system, after first low tens of gigabytes extracted the process hangs in iowait indefinitely. One CPU core is 100% occupied with iowait, the other CPU core is idle (on 2-core Intel Celeron G1610T).
It was bisected to c9fa563072e1 ("xfs: use alloc_pages_bulk_array() for buffers") but XFS is only the messenger. The problem is that nothing is waking kswapd to reclaim some pages at a time the PCP lists cannot be refilled until some reclaim happens. The bulk allocator checks that there are some pages in the array and the original intent was that a bulk allocator did not necessarily need all the requested pages and it was best to return as quickly as possible.
This was fine for the first user of the API but both NFS and XFS require the requested number of pages be available before making progress. Both could be adjusted to call the page allocator directly if a bulk allocation fails but it puts a burden on users of the API. Adjust the semantics to attempt at least one allocation via __alloc_pages() before returning so kswapd is woken if necessary.
It was reported via bugzilla that the patch addressed the problem and that the tar extraction completed successfully. This may also address bug 215975 but has yet to be confirmed.
--- mm/page_alloc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
mm/page_alloc.c +2 -2
@@ -5299,8 +5299,8 @@ unsigned long __alloc_pages_bulk(gfp_t g page =__rmqueue_pcplist (zone,0 , ac.migratetype, alloc_flags, pcp, pcp_list);if (unlikely (!page)) { -/* Try and get at least one page */ -if (!nr_populated) +/* Try and allocate at least one page */ +if (!nr_account) goto failed_irq;break ; }
Greg Kroah-Hartman
maintainerPATCH 621/667 nodemask.h: fix compilation error with GCC12
In reply to Greg Kroah-HartmanFrom: Christophe de Dinechin <[email protected]>
commit 37462a920392cb86541650a6f4121155f11f1199 upstream.
With gcc version 12.0.1 20220401 (Red Hat 12.0.1-0), building with defconfig results in the following compilation error:
| CC mm/swapfile.o | mm/swapfile.c: In function `setup_swap_info': | mm/swapfile.c:2291:47: error: array subscript -1 is below array bounds | of `struct plist_node[]' [-Werror=array-bounds] | 2291 | p->avail_lists[i].prio = 1; | | ~~~~~~~~~~~~~~^~~ | In file included from mm/swapfile.c:16: | ./include/linux/swap.h:292:27: note: while referencing `avail_lists' | 292 | struct plist_node avail_lists[]; /* | | ^~~~~~~~~~~
This is due to the compiler detecting that the mask in node_states[__state] could theoretically be zero, which would lead to first_node() returning -1 through find_first_bit.
I believe that the warning/error is legitimate. I first tried adding a test to check that the node mask is not emtpy, since a similar test exists in the case where MAX_NUMNODES == 1.
However, adding the if statement causes other warnings to appear in for_each_cpu_node_but, because it introduces a dangling else ambiguity. And unfortunately, GCC is not smart enough to detect that the added test makes the case where (node) == -1 impossible, so it still complains with the same message.
This is why I settled on replacing that with a harmless, but relatively useless (node) >= 0 test. Based on the warning for the dangling else, I also decided to fix the case where MAX_NUMNODES == 1 by moving the condition inside the for loop. It will still only be tested once. This ensures that the meaning of an else following for_each_node_mask or derivatives would not silently have a different meaning depending on the configuration.
--- include/linux/nodemask.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
include/linux/nodemask.h +6 -7
@@ -375,14 +375,13 @@ static inline void __nodes_fold(nodemask }#if MAX_NUMNODES >1 -#define for_each_node_mask (node, mask) \ - for ((node) = first_node(mask); \ - (node) < MAX_NUMNODES; \ - (node) = next_node((node), (mask))) +#define for_each_node_mask (node, mask) \ + for ((node) = first_node(mask); \ + (node >= 0) && (node) < MAX_NUMNODES; \ + (node) = next_node((node), (mask)))#else /* MAX_NUMNODES == 1 */ -#define for_each_node_mask (node, mask) \ - if (!nodes_empty(mask)) \ - for ((node) = 0; (node) < 1; (node)++) +#define for_each_node_mask (node, mask) \ + for ((node) = 0; (node) < 1 && !nodes_empty(mask); (node)++)#endif /* MAX_NUMNODES */ /*
Greg Kroah-Hartman
maintainerPATCH 622/667 hugetlb: fix huge_pmd_unshare address update
In reply to Greg Kroah-HartmanFrom: Mike Kravetz <[email protected]>
commit 48381273f8734d28ef56a5bdf1966dd8530111bc upstream.
The routine huge_pmd_unshare() is passed a pointer to an address associated with an area which may be unshared. If unshare is successful this address is updated to 'optimize' callers iterating over huge page addresses. For the optimization to work correctly, address should be updated to the last huge page in the unmapped/unshared area. However, in the common case where the passed address is PUD_SIZE aligned, the address is incorrectly updated to the address of the preceding huge page. That wastes CPU cycles as the unmapped/unshared range is scanned twice.
--- mm/hugetlb.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
mm/hugetlb.c +8 -1
@@ -6060,7 +6060,14 @@ int huge_pmd_unshare(struct mm_struct *mpud_clear (pud);put_page (virt_to_page (ptep));mm_dec_nr_pmds (mm); - *addr =ALIGN (*addr,HPAGE_SIZE *PTRS_PER_PTE ) -HPAGE_SIZE ; +/* +* This update of passed address optimizes loops sequentially +* processing addresses in increments of huge page size (PMD_SIZE +* in this case). By clearing the pud, a PUD_SIZE area is unmapped. +* Update address to the 'last page' in the cleared area so that +* calling loop can move to first page past this area. +*/ + *addr |=PUD_SIZE -PMD_SIZE ;return 1 ; }
Greg Kroah-Hartman
maintainerPATCH 623/667 mm/memremap: fix missing call to untrack_pfn() in pagemap_range()
In reply to Greg Kroah-HartmanFrom: Miaohe Lin <[email protected]>
commit a04e1928e2ead144dc2f369768bc0a0f3110af89 upstream.
We forget to call untrack_pfn() to pair with track_pfn_remap() when range is not allowed to hotplug. Fix it by jump err_kasan.
--- mm/memremap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
mm/memremap.c +1 -1
@@ -245,7 +245,7 @@ static int pagemap_range(struct dev_pageif (!mhp_range_allowed (range->start,range_len (range), !is_private)) { error = -EINVAL ; - goto err_pfn_remap; + goto err_kasan; }mem_hotplug_begin ();
Greg Kroah-Hartman
maintainerPATCH 624/667 xtensa/simdisk: fix proc_read_simdisk()
In reply to Greg Kroah-HartmanFrom: Yi Yang <[email protected]>
commit b011946d039d66bbc7102137e98cc67e1356aa87 upstream.
The commit a69755b18774 ("xtensa simdisk: switch to proc_create_data()") split read operation into two parts, first retrieving the path when it's non-null and second retrieving the trailing '\n'. However when the path is non-null the first simple_read_from_buffer updates ppos, and the second simple_read_from_buffer returns 0 if ppos is greater than 1 (i.e. almost always). As a result reading from that proc file is almost always empty.
Fix it by making a temporary copy of the path with the trailing '\n' and using simple_read_from_buffer on that copy.
--- arch/xtensa/platforms/iss/simdisk.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
arch/xtensa/platforms/iss/simdisk.c +12 -6
@@ -212,12 +212,18 @@ static ssize_t proc_read_simdisk(structstruct simdisk *dev =PDE_DATA (file_inode (file));const char *s = dev->filename;if (s) { -ssize_t n =simple_read_from_buffer (buf, size, ppos, - s,strlen (s)); -if (n <0 ) -return n; - buf += n; - size -= n; +ssize_t len =strlen (s); +char *temp =kmalloc (len +2 ,GFP_KERNEL ); + +if (!temp) +return -ENOMEM ; + + len =scnprintf (temp, len +2 ,"%s\n" , s); + len =simple_read_from_buffer (buf, size, ppos, + temp, len); + +kfree (temp); +return len; }return simple_read_from_buffer (buf, size, ppos,"\n" ,1 ); }
Greg Kroah-Hartman
maintainerPATCH 625/667 rtl818x: Prevent using not initialized queues
In reply to Greg Kroah-HartmanFrom: Alexander Wetzel <[email protected]>
commit 746285cf81dc19502ab238249d75f5990bd2d231 upstream.
Using not existing queues can panic the kernel with rtl8180/rtl8185 cards. Ignore the skb priority for those cards, they only have one tx queue. Pierre Asselin ([email protected]) reported the kernel crash in the Gentoo forum:
https://forums.gentoo.org/viewtopic-t-1147832-postdays-0-postorder-asc-start-25.html
He also confirmed that this patch fixes the issue. In summary this happened:
After updating wpa_supplicant from 2.9 to 2.10 the kernel crashed with a "divide error: 0000" when connecting to an AP. Control port tx now tries to use IEEE80211_AC_VO for the priority, which wpa_supplicants starts to use in 2.10.
Since only the rtl8187se part of the driver supports QoS, the priority of the skb is set to IEEE80211_AC_BE (2) by mac80211 for rtl8180/rtl8185 cards.
rtl8180 is then unconditionally reading out the priority and finally crashes on drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c line 544 without this patch:
idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries
"ring->entries" is zero for rtl8180/rtl8185 cards, tx_ring[2] never got initialized.
--- drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c +6 -2
@@ -460,8 +460,10 @@ static void rtl8180_tx(struct ieee80211_struct rtl8180_priv *priv = dev->priv;struct rtl8180_tx_ring *ring;struct rtl8180_tx_desc *entry; +unsigned int prio =0 ;unsigned long flags; -unsigned int idx, prio, hw_prio; +unsigned int idx, hw_prio; +dma_addr_t mapping;u32 tx_flags;u8 rc_flags;
@@ -470,7 +472,9 @@ static void rtl8180_tx(struct ieee80211_/* do arithmetic and then convert to le16 */ u16 frame_duration =0 ; - prio =skb_get_queue_mapping (skb); +/* rtl8180/rtl8185 only has one useable tx queue */ +if (dev->queues >IEEE80211_AC_BK ) + prio =skb_get_queue_mapping (skb); ring = &priv->tx_ring[prio]; mapping = dma_map_single(&priv->pdev->dev, skb->data, skb->len,
Greg Kroah-Hartman
maintainerPATCH 626/667 ASoC: rt5514: Fix event generation for "DSP Voice Wake Up" control
In reply to Greg Kroah-HartmanFrom: Mark Brown <[email protected]>
commit 4213ff556740bb45e2d9ff0f50d056c4e7dd0921 upstream.
The driver has a custom put function for "DSP Voice Wake Up" which does not generate event notifications on change, instead returning 0. Since we already exit early in the case that there is no change this can be fixed by unconditionally returning 1 at the end of the function.
--- sound/soc/codecs/rt5514.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
sound/soc/codecs/rt5514.c +1 -1
@@ -419,7 +419,7 @@ static int rt5514_dsp_voice_wake_up_put( } } -return 0 ; +return 1 ; }static const struct snd_kcontrol_new rt5514_snd_controls[] = {
Greg Kroah-Hartman
maintainerPATCH 627/667 carl9170: tx: fix an incorrect use of list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 54a6f29522da3c914da30e50721dedf51046449a upstream.
If the previous list_for_each_entry_continue_rcu() don't exit early (no goto hit inside the loop), the iterator 'cvif' after the loop will be a bogus pointer to an invalid structure object containing the HEAD (&ar->vif_list). As a result, the use of 'cvif' after that will lead to a invalid memory access (i.e., 'cvif->id': the invalid pointer dereference when return back to/after the callsite in the carl9170_update_beacon()).
The original intention should have been to return the valid 'cvif' when found in list, NULL otherwise. So just return NULL when no entry found, to fix this bug.
--- drivers/net/wireless/ath/carl9170/tx.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/wireless/ath/carl9170/tx.c +3 -0
@@ -1558,6 +1558,9 @@ static struct carl9170_vif_info *carl917 goto out; } }while (ar->beacon_enabled && i--); + +/* no entry found in list */ +return NULL ; } out:
Greg Kroah-Hartman
maintainerPATCH 628/667 stm: ltdc: fix two incorrect NULL checks on list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 2e6c86be0e57079d1fb6c7c7e5423db096d0548a upstream.
The two bugs are here:
if (encoder) {
if (bridge && bridge->timings)The list iterator value 'encoder/bridge' will *always* be set and non-NULL by drm_for_each_encoder()/list_for_each_entry(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element is found.
To fix the bug, use a new variable '*_iter' as the list iterator, while use the old variable 'encoder/bridge' as a dedicated pointer to point to the found element.
--- drivers/gpu/drm/stm/ltdc.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
drivers/gpu/drm/stm/ltdc.c +10 -6
@@ -528,8 +528,8 @@ static void ltdc_crtc_mode_set_nofb(strustruct drm_device *ddev = crtc->dev;struct drm_connector_list_iter iter;struct drm_connector *connector =NULL ; -struct drm_encoder *encoder =NULL ; -struct drm_bridge *bridge =NULL ; +struct drm_encoder *encoder =NULL , *en_iter; +struct drm_bridge *bridge =NULL , *br_iter;struct drm_display_mode *mode = &crtc->state->adjusted_mode;u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h;u32 total_width, total_height;
@@ -538,15 +538,19 @@ static void ltdc_crtc_mode_set_nofb(struint ret;/* get encoder from crtc */ -drm_for_each_encoder (encoder, ddev) -if (encoder->crtc == crtc) +drm_for_each_encoder (en_iter, ddev) +if (en_iter->crtc == crtc) { + encoder = en_iter;break ; + }if (encoder) {/* get bridge from encoder */ -list_for_each_entry (bridge, &encoder->bridge_chain, chain_node) -if (bridge->encoder == encoder) +list_for_each_entry (br_iter, &encoder->bridge_chain, chain_node) +if (br_iter->encoder == encoder) { + bridge = br_iter;break ; + }/* Get the connector from encoder */ drm_connector_list_iter_begin (ddev, &iter);
Greg Kroah-Hartman
maintainerPATCH 629/667 bcache: improve multithreaded bch_btree_check()
In reply to Greg Kroah-HartmanFrom: Coly Li <[email protected]>
commit 622536443b6731ec82c563aae7807165adbe9178 upstream.
Commit 8e7102273f59 ("bcache: make bch_btree_check() to be multithreaded") makes bch_btree_check() to be much faster when checking all btree nodes during cache device registration. But it isn't in ideal shap yet, still can be improved.
This patch does the following thing to improve current parallel btree nodes check by multiple threads in bch_btree_check(),
- Add read lock to root node while checking all the btree nodes with multiple threads. Although currently it is not mandatory but it is good to have a read lock in code logic.
- Remove local variable 'char name[32]', and generate kernel thread name string directly when calling kthread_run().
- Allocate local variable "struct btree_check_state check_state" on the stack and avoid unnecessary dynamic memory allocation for it.
- Reduce BCH_BTR_CHKTHREAD_MAX from 64 to 12 which is enough indeed.
- Increase check_state->started to count created kernel thread after it succeeds to create.
- When wait for all checking kernel threads to finish, use wait_event() to replace wait_event_interruptible().
With this change, the code is more clear, and some potential error conditions are avoided.
--- drivers/md/bcache/btree.c | 58 ++++++++++++++++++++-------------------------- drivers/md/bcache/btree.h | 2 - 2 files changed, 27 insertions(+), 33 deletions(-)
drivers/md/bcache/btree.c +26 -32
@@ -2006,8 +2006,7 @@ int bch_btree_check(struct cache_set *c)int i;struct bkey *k =NULL ;struct btree_iter iter; -struct btree_check_state *check_state; -char name[32 ]; +struct btree_check_state check_state;/* check and mark root node keys */ for_each_key_filter (&c->root->keys, k, &iter, bch_ptr_invalid)
@@ -2018,63 +2017,58 @@ int bch_btree_check(struct cache_set *c)if (c->root->level ==0 )return 0 ; - check_state =kzalloc (sizeof (struct btree_check_state ),GFP_KERNEL ); -if (!check_state) -return -ENOMEM ; - - check_state->c = c; - check_state->total_threads =bch_btree_chkthread_nr (); - check_state->key_idx =0 ; -spin_lock_init (&check_state->idx_lock); -atomic_set (&check_state->started,0 ); -atomic_set (&check_state->enough,0 ); -init_waitqueue_head (&check_state->wait); + check_state.c = c; + check_state.total_threads =bch_btree_chkthread_nr (); + check_state.key_idx =0 ; +spin_lock_init (&check_state.idx_lock); +atomic_set (&check_state.started,0 ); +atomic_set (&check_state.enough,0 ); +init_waitqueue_head (&check_state.wait); +rw_lock (0 , c->root, c->root->level);/* * Run multiple threads to check btree nodes in parallel, -* if check_state->enough is non-zero, it means current +* if check_state.enough is non-zero, it means current * running check threads are enough, unncessary to create * more. */ -for (i =0 ; i < check_state->total_threads; i++) { -/* fetch latest check_state->enough earlier */ +for (i =0 ; i < check_state.total_threads; i++) { +/* fetch latest check_state.enough earlier */ smp_mb__before_atomic (); -if (atomic_read (&check_state->enough)) +if (atomic_read (&check_state.enough))break ; - check_state->infos[i].result =0 ; - check_state->infos[i].state = check_state; -snprintf (name,sizeof (name),"bch_btrchk[%u]" , i); -atomic_inc (&check_state->started); + check_state.infos[i].result =0 ; + check_state.infos[i].state = &check_state; - check_state->infos[i].thread = + check_state.infos[i].thread =kthread_run (bch_btree_check_thread, - &check_state->infos[i], - name); -if (IS_ERR (check_state->infos[i].thread)) { + &check_state.infos[i], +"bch_btrchk[%d]" , i); +if (IS_ERR (check_state.infos[i].thread)) {pr_err ("fails to run thread bch_btrchk[%d]\n" , i);for (--i; i >=0 ; i--) -kthread_stop (check_state->infos[i].thread); +kthread_stop (check_state.infos[i].thread); ret = -ENOMEM ; goto out; } +atomic_inc (&check_state.started); }/* * Must wait for all threads to stop. */ -wait_event_interruptible (check_state->wait, -atomic_read (&check_state->started) ==0 ); +wait_event (check_state.wait,atomic_read (&check_state.started) ==0 ); -for (i =0 ; i < check_state->total_threads; i++) { -if (check_state->infos[i].result) { - ret = check_state->infos[i].result; +for (i =0 ; i < check_state.total_threads; i++) { +if (check_state.infos[i].result) { + ret = check_state.infos[i].result; goto out; } } out: -kfree (check_state); +rw_unlock (0 , c->root);return ret; }
drivers/md/bcache/btree.h +1 -1
@@ -226,7 +226,7 @@ struct btree_check_info {int result; }; -#define BCH_BTR_CHKTHREAD_MAX 64 +#define BCH_BTR_CHKTHREAD_MAX 12struct btree_check_state {struct cache_set *c;int total_threads;
Greg Kroah-Hartman
maintainerPATCH 630/667 bcache: improve multithreaded bch_sectors_dirty_init()
In reply to Greg Kroah-HartmanFrom: Coly Li <[email protected]>
commit 4dc34ae1b45fe26e772a44379f936c72623dd407 upstream.
Commit b144e45fc576 ("bcache: make bch_sectors_dirty_init() to be multithreaded") makes bch_sectors_dirty_init() to be much faster when counting dirty sectors by iterating all dirty keys in the btree. But it isn't in ideal shape yet, still can be improved.
This patch does the following changes to improve current parallel dirty keys iteration on the btree,
- Add read lock to root node when multiple threads iterating the btree, to prevent the root node gets split by I/Os from other registered bcache devices.
- Remove local variable "char name[32]" and generate kernel thread name string directly when calling kthread_run().
- Allocate "struct bch_dirty_init_state state" directly on stack and avoid the unnecessary dynamic memory allocation for it.
- Decrease BCH_DIRTY_INIT_THRD_MAX from 64 to 12 which is enough indeed.
- Increase &state->started to count created kernel thread after it succeeds to create.
- When wait for all dirty key counting threads to finish, use wait_event() to replace wait_event_interruptible().
With the above changes, the code is more clear, and some potential error conditions are avoided.
--- drivers/md/bcache/writeback.c | 60 ++++++++++++++++-------------------------- drivers/md/bcache/writeback.h | 2 - 2 files changed, 25 insertions(+), 37 deletions(-)
drivers/md/bcache/writeback.c +24 -36
@@ -945,10 +945,10 @@ void bch_sectors_dirty_init(struct bcachstruct btree_iter iter;struct sectors_dirty_init op;struct cache_set *c = d->c; -struct bch_dirty_init_state *state; -char name[32 ]; +struct bch_dirty_init_state state;/* Just count root keys if no leaf node */ +rw_lock (0 , c->root, c->root->level);if (c->root->level ==0 ) {bch_btree_op_init (&op.op,-1 ); op.inode = d->id;
@@ -958,54 +958,42 @@ void bch_sectors_dirty_init(struct bcachfor_each_key_filter (&c->root->keys, k, &iter, bch_ptr_invalid)sectors_dirty_init_fn (&op.op, c->root, k); +rw_unlock (0 , c->root);return ; } - state =kzalloc (sizeof (struct bch_dirty_init_state ),GFP_KERNEL ); -if (!state) { -pr_warn ("sectors dirty init failed: cannot allocate memory\n" ); -return ; - } + state.c = c; + state.d = d; + state.total_threads =bch_btre_dirty_init_thread_nr (); + state.key_idx =0 ; +spin_lock_init (&state.idx_lock); +atomic_set (&state.started,0 ); +atomic_set (&state.enough,0 ); +init_waitqueue_head (&state.wait); - state->c = c; - state->d = d; - state->total_threads =bch_btre_dirty_init_thread_nr (); - state->key_idx =0 ; -spin_lock_init (&state->idx_lock); -atomic_set (&state->started,0 ); -atomic_set (&state->enough,0 ); -init_waitqueue_head (&state->wait); - -for (i =0 ; i < state->total_threads; i++) { -/* Fetch latest state->enough earlier */ +for (i =0 ; i < state.total_threads; i++) { +/* Fetch latest state.enough earlier */ smp_mb__before_atomic (); -if (atomic_read (&state->enough)) +if (atomic_read (&state.enough))break ; - state->infos[i].state = state; -atomic_inc (&state->started); -snprintf (name,sizeof (name),"bch_dirty_init[%d]" , i); - - state->infos[i].thread = -kthread_run (bch_dirty_init_thread, - &state->infos[i], - name); -if (IS_ERR (state->infos[i].thread)) { + state.infos[i].state = &state; + state.infos[i].thread = +kthread_run (bch_dirty_init_thread, &state.infos[i], +"bch_dirtcnt[%d]" , i); +if (IS_ERR (state.infos[i].thread)) {pr_err ("fails to run thread bch_dirty_init[%d]\n" , i);for (--i; i >=0 ; i--) -kthread_stop (state->infos[i].thread); +kthread_stop (state.infos[i].thread); goto out; } +atomic_inc (&state.started); } -/* -* Must wait for all threads to stop. -*/ -wait_event_interruptible (state->wait, -atomic_read (&state->started) ==0 ); - out: -kfree (state); +/* Must wait for all threads to stop. */ +wait_event (state.wait,atomic_read (&state.started) ==0 ); +rw_unlock (0 , c->root); }void bch_cached_dev_writeback_init (struct cached_dev *dc)
drivers/md/bcache/writeback.h +1 -1
@@ -20,7 +20,7 @@#define BCH_WRITEBACK_FRAGMENT_THRESHOLD_MID 57#define BCH_WRITEBACK_FRAGMENT_THRESHOLD_HIGH 64 -#define BCH_DIRTY_INIT_THRD_MAX 64 +#define BCH_DIRTY_INIT_THRD_MAX 12/* * 14 (16384ths) is chosen here as something that each backing device * should be a reasonable fraction of the share, and not to blow up
Greg Kroah-Hartman
maintainerPATCH 631/667 bcache: remove incremental dirty sector counting for bch_sectors_dirty_init()
In reply to Greg Kroah-HartmanFrom: Coly Li <[email protected]>
commit 80db4e4707e78cb22287da7d058d7274bd4cb370 upstream.
After making bch_sectors_dirty_init() being multithreaded, the existing incremental dirty sector counting in bch_root_node_dirty_init() doesn't release btree occupation after iterating 500000 (INIT_KEYS_EACH_TIME) bkeys. Because a read lock is added on btree root node to prevent the btree to be split during the dirty sectors counting, other I/O requester has no chance to gain the write lock even restart bcache_btree().
That is to say, the incremental dirty sectors counting is incompatible to the multhreaded bch_sectors_dirty_init(). We have to choose one and drop another one.
In my testing, with 512 bytes random writes, I generate 1.2T dirty data and a btree with 400K nodes. With single thread and incremental dirty sectors counting, it takes 30+ minites to register the backing device. And with multithreaded dirty sectors counting, the backing device registration can be accomplished within 2 minutes.
The 30+ minutes V.S. 2- minutes difference makes me decide to keep multithreaded bch_sectors_dirty_init() and drop the incremental dirty sectors counting. This is what this patch does.
But INIT_KEYS_EACH_TIME is kept, in sectors_dirty_init_fn() the CPU will be released by cond_resched() after every INIT_KEYS_EACH_TIME keys iterated. This is to avoid the watchdog reports a bogus soft lockup warning.
--- drivers/md/bcache/writeback.c | 39 ++++++++++++--------------------------- 1 file changed, 12 insertions(+), 27 deletions(-)
drivers/md/bcache/writeback.c +12 -27
@@ -802,13 +802,11 @@ static int bch_writeback_thread(void *ar/* Init */ #define INIT_KEYS_EACH_TIME 500000 -#define INIT_KEYS_SLEEP_MS 100struct sectors_dirty_init {struct btree_op op;unsigned int inode;size_t count; -struct bkey start; }; static int sectors_dirty_init_fn(struct btree_op *_op, struct btree *b,
@@ -824,11 +822,8 @@ static int sectors_dirty_init_fn(struct KEY_START(k), KEY_SIZE(k)); op->count++; -if (atomic_read (&b->c->search_inflight) && - !(op->count %INIT_KEYS_EACH_TIME )) { -bkey_copy_key (&op->start, k); -return -EAGAIN ; - } +if (!(op->count %INIT_KEYS_EACH_TIME )) +cond_resched ();return MAP_CONTINUE ; }
@@ -843,24 +838,16 @@ static int bch_root_node_dirty_init(strubch_btree_op_init (&op.op,-1 ); op.inode = d->id; op.count =0 ; - op.start =KEY (op.inode,0 ,0 ); -do { - ret =bcache_btree (map_keys_recurse, - k, - c->root, - &op.op, - &op.start, - sectors_dirty_init_fn, -0 ); -if (ret == -EAGAIN ) -schedule_timeout_interruptible ( -msecs_to_jiffies (INIT_KEYS_SLEEP_MS )); -else if (ret <0 ) { -pr_warn ("sectors dirty init failed, ret=%d!\n" , ret); -break ; - } - }while (ret == -EAGAIN ); + ret =bcache_btree (map_keys_recurse, + k, + c->root, + &op.op, + &KEY (op.inode,0 ,0 ), + sectors_dirty_init_fn, +0 ); +if (ret <0 ) +pr_warn ("sectors dirty init failed, ret=%d!\n" , ret);return ret; }
@@ -904,7 +891,6 @@ static int bch_dirty_init_thread(void *a goto out; } skip_nr--; -cond_resched (); }if (p) {
@@ -914,7 +900,6 @@ static int bch_dirty_init_thread(void *a p =NULL ; prev_idx = cur_idx; -cond_resched (); } out:
@@ -953,11 +938,11 @@ void bch_sectors_dirty_init(struct bcachbch_btree_op_init (&op.op,-1 ); op.inode = d->id; op.count =0 ; - op.start =KEY (op.inode,0 ,0 );for_each_key_filter (&c->root->keys, k, &iter, bch_ptr_invalid)sectors_dirty_init_fn (&op.op, c->root, k); +rw_unlock (0 , c->root);return ; }
Greg Kroah-Hartman
maintainerPATCH 632/667 bcache: avoid journal no-space deadlock by reserving 1 journal bucket
In reply to Greg Kroah-HartmanFrom: Coly Li <[email protected]>
commit 32feee36c30ea06e38ccb8ae6e5c44c6eec790a6 upstream.
The journal no-space deadlock was reported time to time. Such deadlock can happen in the following situation.
When all journal buckets are fully filled by active jset with heavy write I/O load, the cache set registration (after a reboot) will load all active jsets and inserting them into the btree again (which is called journal replay). If a journaled bkey is inserted into a btree node and results btree node split, new journal request might be triggered. For example, the btree grows one more level after the node split, then the root node record in cache device super block will be upgrade by bch_journal_meta() from bch_btree_set_root(). But there is no space in journal buckets, the journal replay has to wait for new journal bucket to be reclaimed after at least one journal bucket replayed. This is one example that how the journal no-space deadlock happens.
The solution to avoid the deadlock is to reserve 1 journal bucket in run time, and only permit the reserved journal bucket to be used during cache set registration procedure for things like journal replay. Then the journal space will never be fully filled, there is no chance for journal no-space deadlock to happen anymore.
This patch adds a new member "bool do_reserve" in struct journal, it is inititalized to 0 (false) when struct journal is allocated, and set to 1 (true) by bch_journal_space_reserve() when all initialization done in run_cache_set(). In the run time when journal_reclaim() tries to allocate a new journal bucket, free_journal_buckets() is called to check whether there are enough free journal buckets to use. If there is only 1 free journal bucket and journal->do_reserve is 1 (true), the last bucket is reserved and free_journal_buckets() will return 0 to indicate no free journal bucket. Then journal_reclaim() will give up, and try next time to see whetheer there is free journal bucket to allocate. By this method, there is always 1 jouranl bucket reserved in run time.
During the cache set registration, journal->do_reserve is 0 (false), so the reserved journal bucket can be used to avoid the no-space deadlock.
--- drivers/md/bcache/journal.c | 31 ++++++++++++++++++++++++++----- drivers/md/bcache/journal.h | 2 ++ drivers/md/bcache/super.c | 1 + 3 files changed, 29 insertions(+), 5 deletions(-)
drivers/md/bcache/journal.c +26 -5
@@ -407,6 +407,11 @@ err:return ret; } +void bch_journal_space_reserve (struct journal *j) +{ + j->do_reserve = true; +} +/* Journalling */ static void btree_flush_write (struct cache_set *c)
@@ -625,12 +630,30 @@ static void do_journal_discard(struct ca } } +static unsigned int free_journal_buckets (struct cache_set *c) +{ +struct journal *j = &c->journal; +struct cache *ca = c->cache; +struct journal_device *ja = &c->cache->journal; +unsigned int n; + +/* In case njournal_buckets is not power of 2 */ +if (ja->cur_idx >= ja->discard_idx) + n = ca->sb.njournal_buckets + ja->discard_idx - ja->cur_idx; +else + n = ja->discard_idx - ja->cur_idx; + +if (n > (1 + j->do_reserve)) +return n - (1 + j->do_reserve); + +return 0 ; +} +static void journal_reclaim (struct cache_set *c) {struct bkey *k = &c->journal.key;struct cache *ca = c->cache;uint64_t last_seq; -unsigned int next;struct journal_device *ja = &ca->journal;atomic_t p__maybe_unused ;
@@ -653,12 +676,10 @@ static void journal_reclaim(struct cacheif (c->journal.blocks_free) goto out; - next = (ja->cur_idx +1 ) % ca->sb.njournal_buckets; -/* No space available on this device */ -if (next == ja->discard_idx) +if (!free_journal_buckets (c)) goto out; - ja->cur_idx = next; + ja->cur_idx = (ja->cur_idx +1 ) % ca->sb.njournal_buckets; k->ptr[0 ] =MAKE_PTR (0 ,bucket_to_sector (c, ca->sb.d[ja->cur_idx]), ca->sb.nr_this_dev);
drivers/md/bcache/journal.h +2 -0
@@ -105,6 +105,7 @@ struct journal {spinlock_t lock;spinlock_t flush_write_lock;bool btree_flushing; +bool do_reserve;/* used when waiting because the journal was full */ struct closure_waitlist wait;struct closure io;
@@ -182,5 +183,6 @@ int bch_journal_replay(struct cache_setvoid bch_journal_free (struct cache_set *c);int bch_journal_alloc (struct cache_set *c); +void bch_journal_space_reserve (struct journal *j);#endif /* _BCACHE_JOURNAL_H */
drivers/md/bcache/super.c +1 -0
@@ -2131,6 +2131,7 @@ static int run_cache_set(struct cache_seflash_devs_run (c); +bch_journal_space_reserve (&c->journal);set_bit (CACHE_SET_RUNNING , &c->flags);return 0 ; err:
Greg Kroah-Hartman
maintainerPATCH 633/667 serial: pch: dont overwrite xmit->buf[0] by x_char
In reply to Greg Kroah-HartmanFrom: Jiri Slaby <[email protected]>
commit d9f3af4fbb1d955bbaf872d9e76502f6e3e803cb upstream.
When x_char is to be sent, the TX path overwrites whatever is in the circular buffer at offset 0 with x_char and sends it using pch_uart_hal_write(). I don't understand how this was supposed to work if xmit->buf[0] already contained some character. It must have been lost.
Remove this whole pop_tx_x() concept and do the work directly in the callers. (Without printing anything using dev_dbg().)
--- drivers/tty/serial/pch_uart.c | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-)
drivers/tty/serial/pch_uart.c +7 -20
@@ -624,22 +624,6 @@ static int push_rx(struct eg20t_port *prreturn 0 ; } -static int pop_tx_x (struct eg20t_port *priv,unsigned char *buf) -{ -int ret =0 ; -struct uart_port *port = &priv->port; - -if (port->x_char) { -dev_dbg (priv->port.dev,"%s:X character send %02x (%lu)\n" , - __func__, port->x_char, jiffies); - buf[0 ] = port->x_char; - port->x_char =0 ; - ret =1 ; - } - -return ret; -} -static int dma_push_rx (struct eg20t_port *priv,int size) {int room;
@@ -889,9 +873,10 @@ static unsigned int handle_tx(struct eg2 fifo_size =max (priv->fifo_size,1 ); tx_empty =1 ; -if (pop_tx_x (priv, xmit->buf)) { -pch_uart_hal_write (priv, xmit->buf,1 ); +if (port->x_char) { +pch_uart_hal_write (priv, &port->x_char,1 ); port->icount.tx++; + port->x_char =0 ; tx_empty =0 ; fifo_size--; }
@@ -946,9 +931,11 @@ static unsigned int dma_handle_tx(struct } fifo_size =max (priv->fifo_size,1 ); -if (pop_tx_x (priv, xmit->buf)) { -pch_uart_hal_write (priv, xmit->buf,1 ); + +if (port->x_char) { +pch_uart_hal_write (priv, &port->x_char,1 ); port->icount.tx++; + port->x_char =0 ; fifo_size--; }
Greg Kroah-Hartman
maintainerPATCH 634/667 tilcdc: tilcdc_external: fix an incorrect NULL check on list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit 8b917cbe38e9b0d002492477a9fc2bfee2412ce4 upstream.
The bug is here:
if (!encoder) {The list iterator value 'encoder' will *always* be set and non-NULL by list_for_each_entry(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element is found.
To fix the bug, use a new variable 'iter' as the list iterator, while use the original variable 'encoder' as a dedicated pointer to point to the found element.
--- drivers/gpu/drm/tilcdc/tilcdc_external.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/gpu/drm/tilcdc/tilcdc_external.c +5 -3
@@ -60,11 +60,13 @@ struct drm_connector *tilcdc_encoder_finint tilcdc_add_component_encoder (struct drm_device *ddev) {struct tilcdc_drm_private *priv = ddev->dev_private; -struct drm_encoder *encoder; +struct drm_encoder *encoder =NULL , *iter; -list_for_each_entry (encoder, &ddev->mode_config.encoder_list, head) -if (encoder->possible_crtcs & (1 << priv->crtc->index)) +list_for_each_entry (iter, &ddev->mode_config.encoder_list, head) +if (iter->possible_crtcs & (1 << priv->crtc->index)) { + encoder = iter;break ; + }if (!encoder) {dev_err (ddev->dev,"%s: No suitable encoder found\n" , __func__);
Greg Kroah-Hartman
maintainerPATCH 635/667 gma500: fix an incorrect NULL check on list iterator
In reply to Greg Kroah-HartmanFrom: Xiaomeng Tong <[email protected]>
commit bdef417d84536715145f6dc9cc3275c46f26295a upstream.
The bug is here:
return crtc;
The list iterator value 'crtc' will *always* be set and non-NULL by list_for_each_entry(), so it is incorrect to assume that the iterator value will be NULL if the list is empty or no element is found.
To fix the bug, return 'crtc' when found, otherwise return NULL.
--- drivers/gpu/drm/gma500/psb_intel_display.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/gpu/drm/gma500/psb_intel_display.c +4 -3
@@ -536,14 +536,15 @@ void psb_intel_crtc_init(struct drm_devistruct drm_crtc *psb_intel_get_crtc_from_pipe (struct drm_device *dev,int pipe) { -struct drm_crtc *crtc =NULL ; +struct drm_crtc *crtc;list_for_each_entry (crtc, &dev->mode_config.crtc_list, head) {struct gma_crtc *gma_crtc =to_gma_crtc (crtc); +if (gma_crtc->pipe == pipe) -break ; +return crtc; } -return crtc; +return NULL ; }int gma_connector_clones (struct drm_device *dev,int type_mask)
Greg Kroah-Hartman
maintainerPATCH 636/667 arm64: dts: qcom: ipq8074: fix the sleep clock frequency
In reply to Greg Kroah-HartmanFrom: Kathiravan T <[email protected]>
commit f607dd767f5d6800ffbdce5b99ba81763b023781 upstream.
Sleep clock frequency should be 32768Hz. Lets fix it.
--- arch/arm64/boot/dts/qcom/ipq8074.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/boot/dts/qcom/ipq8074.dtsi +1 -1
@@ -13,7 +13,7 @@ clocks { sleep_clk: sleep_clk { compatible = "fixed-clock"; - clock-frequency = <32000>; + clock-frequency = <32768>; #clock-cells = <0>; };
Greg Kroah-Hartman
maintainerPATCH 637/667 arm64: tegra: Add missing DFLL reset on Tegra210
In reply to Greg Kroah-HartmanFrom: Diogo Ivo <[email protected]>
commit 0017f2c856e21bb900be88469e15dac4f41f4065 upstream.
Commit 4782c0a5dd88 ("clk: tegra: Don't deassert reset on enabling clocks") removed deassertion of reset lines when enabling peripheral clocks. This breaks the initialization of the DFLL driver which relied on this behaviour.
In order to be able to fix this, add the corresponding reset to the DT. Tested on Google Pixel C.
--- arch/arm64/boot/dts/nvidia/tegra210.dtsi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
arch/arm64/boot/dts/nvidia/tegra210.dtsi +3 -2
@@ -1355,8 +1355,9 @@ <&tegra_car TEGRA210_CLK_DFLL_REF>, <&tegra_car TEGRA210_CLK_I2C5>; clock-names = "soc", "ref", "i2c"; - resets = <&tegra_car TEGRA210_RST_DFLL_DVCO>; - reset-names = "dvco"; + resets = <&tegra_car TEGRA210_RST_DFLL_DVCO>, + <&tegra_car 155>; + reset-names = "dvco", "dfll"; #clock-cells = <0>; clock-output-names = "dfllCPU_out"; status = "disabled";
Greg Kroah-Hartman
maintainerPATCH 638/667 clk: tegra: Add missing reset deassertion
In reply to Greg Kroah-HartmanFrom: Diogo Ivo <[email protected]>
commit 23a43cc437e747473d5f8f98b4fe189fb5c433b7 upstream.
Commit 4782c0a5dd88 ("clk: tegra: Don't deassert reset on enabling clocks") removed deassertion of reset lines when enabling peripheral clocks. This breaks the initialization of the DFLL driver which relied on this behaviour.
Fix this problem by adding explicit deassert/assert requests to the driver. Tested on Google Pixel C.
--- drivers/clk/tegra/clk-dfll.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/clk/tegra/clk-dfll.c +12 -0
@@ -271,6 +271,7 @@ struct tegra_dfll {struct clk *ref_clk;struct clk *i2c_clk;struct clk *dfll_clk; +struct reset_control *dfll_rst;struct reset_control *dvco_rst;unsigned long ref_rate;unsigned long i2c_clk_rate;
@@ -1464,6 +1465,7 @@ static int dfll_init(struct tegra_dfll *return -EINVAL ; } +reset_control_deassert (td->dfll_rst);reset_control_deassert (td->dvco_rst); ret =clk_prepare (td->ref_clk);
@@ -1509,6 +1511,7 @@ di_err1:clk_unprepare (td->ref_clk);reset_control_assert (td->dvco_rst); +reset_control_assert (td->dfll_rst);return ret; }
@@ -1530,6 +1533,7 @@ int tegra_dfll_suspend(struct device *de }reset_control_assert (td->dvco_rst); +reset_control_assert (td->dfll_rst);return 0 ; }
@@ -1548,6 +1552,7 @@ int tegra_dfll_resume(struct device *dev {struct tegra_dfll *td =dev_get_drvdata (dev); +reset_control_deassert (td->dfll_rst);reset_control_deassert (td->dvco_rst);pm_runtime_get_sync (td->dev);
@@ -1951,6 +1956,12 @@ int tegra_dfll_register(struct platform_ td->soc = soc; + td->dfll_rst =devm_reset_control_get_optional (td->dev,"dfll" ); +if (IS_ERR (td->dfll_rst)) { +dev_err (td->dev,"couldn't get dfll reset\n" ); +return PTR_ERR (td->dfll_rst); + } + td->dvco_rst =devm_reset_control_get (td->dev,"dvco" );if (IS_ERR (td->dvco_rst)) {dev_err (td->dev,"couldn't get dvco reset\n" );
@@ -2087,6 +2098,7 @@ struct tegra_dfll_soc_data *tegra_dfll_uclk_unprepare (td->i2c_clk);reset_control_assert (td->dvco_rst); +reset_control_assert (td->dfll_rst);return td->soc; }
Greg Kroah-Hartman
maintainerPATCH 639/667 phy: qcom-qmp: fix struct clk leak on probe errors
In reply to Greg Kroah-HartmanFrom: Johan Hovold <[email protected]>
commit f0a4bc38a12f5a0cc5ad68670d9480e91e6a94df upstream.
Make sure to release the pipe clock reference in case of a late probe error (e.g. probe deferral).
--- drivers/phy/qualcomm/phy-qcom-qmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/phy/qualcomm/phy-qcom-qmp.c +1 -1
@@ -5454,7 +5454,7 @@ int qcom_qmp_phy_create(struct device *d* all phys that don't need this. */ snprintf (prop_name,sizeof (prop_name),"pipe%d" , id); - qphy->pipe_clk =of_clk_get_by_name (np, prop_name); + qphy->pipe_clk =devm_get_clk_from_child (dev, np, prop_name);if (IS_ERR (qphy->pipe_clk)) {if (cfg->type ==PHY_TYPE_PCIE || cfg->type ==PHY_TYPE_USB3 ) {
Greg Kroah-Hartman
maintainerPATCH 640/667 ARM: dts: s5pv210: Remove spi-cs-high on panel in Aries
In reply to Greg Kroah-HartmanFrom: Jonathan Bakker <[email protected]>
commit 096f58507374e1293a9e9cff8a1ccd5f37780a20 upstream.
Since commit 766c6b63aa04 ("spi: fix client driver breakages when using GPIO descriptors"), the panel has been blank due to an inverted CS GPIO. In order to correct this, drop the spi-cs-high from the panel SPI device.
--- arch/arm/boot/dts/s5pv210-aries.dtsi | 1 - 1 file changed, 1 deletion(-)
arch/arm/boot/dts/s5pv210-aries.dtsi +0 -1
@@ -564,7 +564,6 @@ reset-gpios = <&mp05 5 GPIO_ACTIVE_LOW>; vdd3-supply = <&ldo7_reg>; vci-supply = <&ldo17_reg>; - spi-cs-high; spi-max-frequency = <1200000>; pinctrl-names = "default";
Greg Kroah-Hartman
maintainerPATCH 641/667 ARM: pxa: maybe fix gpio lookup tables
In reply to Greg Kroah-HartmanFrom: Arnd Bergmann <[email protected]>
commit 2672a4bff6c03a20d5ae460a091f67ee782c3eff upstream.
Quoted 1 line
From inspection I found a couple of GPIO lookups that are
listed with device "gpio-pxa", but actually have a number from a different gpio controller.
Try to rectify that here, with a guess of what the actual device name is.
--- arch/arm/mach-pxa/cm-x300.c | 8 ++++---- arch/arm/mach-pxa/magician.c | 2 +- arch/arm/mach-pxa/tosa.c | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-)
arch/arm/mach-pxa/cm-x300.c +4 -4
@@ -354,13 +354,13 @@ static struct platform_device cm_x300_spstatic struct gpiod_lookup_table cm_x300_spi_gpiod_table = { .dev_id ="spi_gpio" , .table = { -GPIO_LOOKUP ("gpio-pxa" ,GPIO_LCD_SCL , +GPIO_LOOKUP ("pca9555.1" ,GPIO_LCD_SCL -GPIO_LCD_BASE ,"sck" ,GPIO_ACTIVE_HIGH ), -GPIO_LOOKUP ("gpio-pxa" ,GPIO_LCD_DIN , +GPIO_LOOKUP ("pca9555.1" ,GPIO_LCD_DIN -GPIO_LCD_BASE ,"mosi" ,GPIO_ACTIVE_HIGH ), -GPIO_LOOKUP ("gpio-pxa" ,GPIO_LCD_DOUT , +GPIO_LOOKUP ("pca9555.1" ,GPIO_LCD_DOUT -GPIO_LCD_BASE ,"miso" ,GPIO_ACTIVE_HIGH ), -GPIO_LOOKUP ("gpio-pxa" ,GPIO_LCD_CS , +GPIO_LOOKUP ("pca9555.1" ,GPIO_LCD_CS -GPIO_LCD_BASE ,"cs" ,GPIO_ACTIVE_HIGH ), { }, },
arch/arm/mach-pxa/magician.c +1 -1
@@ -681,7 +681,7 @@ static struct platform_device bq24022 =static struct gpiod_lookup_table bq24022_gpiod_table = { .dev_id ="gpio-regulator" , .table = { -GPIO_LOOKUP ("gpio-pxa" ,EGPIO_MAGICIAN_BQ24022_ISET2 , +GPIO_LOOKUP ("htc-egpio-0" ,EGPIO_MAGICIAN_BQ24022_ISET2 -MAGICIAN_EGPIO_BASE ,NULL ,GPIO_ACTIVE_HIGH ),GPIO_LOOKUP ("gpio-pxa" , GPIO30_MAGICIAN_BQ24022_nCHARGE_EN,"enable" ,GPIO_ACTIVE_LOW ),
arch/arm/mach-pxa/tosa.c +2 -2
@@ -296,9 +296,9 @@ static struct gpiod_lookup_table tosa_mc .table = {GPIO_LOOKUP ("gpio-pxa" , TOSA_GPIO_nSD_DETECT,"cd" ,GPIO_ACTIVE_LOW ), -GPIO_LOOKUP ("gpio-pxa" ,TOSA_GPIO_SD_WP , +GPIO_LOOKUP ("sharp-scoop.0" ,TOSA_GPIO_SD_WP -TOSA_SCOOP_GPIO_BASE ,"wp" ,GPIO_ACTIVE_LOW ), -GPIO_LOOKUP ("gpio-pxa" ,TOSA_GPIO_PWR_ON , +GPIO_LOOKUP ("sharp-scoop.0" ,TOSA_GPIO_PWR_ON -TOSA_SCOOP_GPIO_BASE , "power", GPIO_ACTIVE_HIGH), { }, },
Greg Kroah-Hartman
maintainerPATCH 642/667 SMB3: EBADF/EIO errors in rename/open caused by race condition in smb2_compound_op
In reply to Greg Kroah-HartmanFrom: Steve French <[email protected]>
commit 0a55cf74ffb5d004b93647e4389096880ce37d6b upstream.
There is a race condition in smb2_compound_op:
after_close:
num_rqst++;
if (cfile) {
cifsFileInfo_put(cfile); // sends SMB2_CLOSE to the server
cfile = NULL;This is triggered by smb2_query_path_info operation that happens during revalidate_dentry. In smb2_query_path_info, get_readable_path is called to load the cfile, increasing the reference counter. If in the meantime, this reference becomes the very last, this call to cifsFileInfo_put(cfile) will trigger a SMB2_CLOSE request sent to the server just before sending this compound request – and so then the compound request fails either with EBADF/EIO depending on the timing at the server, because the handle is already closed.
In the first scenario, the race seems to be happening between smb2_query_path_info triggered by the rename operation, and between “cleanup” of asynchronous writes – while fsync(fd) likely waits for the asynchronous writes to complete, releasing the writeback structures can happen after the close(fd) call. So the EBADF/EIO errors will pop up if the timing is such that:
1) There are still outstanding references after close(fd) in the writeback structures
2) smb2_query_path_info successfully fetches the cfile, increasing the refcounter by 1
3) All writeback structures release the same cfile, reducing refcounter to 1
4) smb2_compound_op is called with that cfile
In the second scenario, the race seems to be similar – here open triggers the smb2_query_path_info operation, and if all other threads in the meantime decrease the refcounter to 1 similarly to the first scenario, again SMB2_CLOSE will be sent to the server just before issuing the compound request. This case is harder to reproduce.
See https://bugzilla.samba.org/show_bug.cgi?id=15051
--- fs/cifs/smb2inode.c | 2 -- 1 file changed, 2 deletions(-)
fs/cifs/smb2inode.c +0 -2
@@ -358,8 +358,6 @@ smb2_compound_op(const unsigned int xid, num_rqst++;if (cfile) { -cifsFileInfo_put (cfile); - cfile =NULL ; rc = compound_send_recv(xid, ses, server, flags, num_rqst - 2, &rqst[1], &resp_buftype[1],
Greg Kroah-Hartman
maintainerPATCH 643/667 docs/conf.py: Cope with removal of language=None in Sphinx 5.0.0
In reply to Greg Kroah-HartmanFrom: Akira Yokosawa <[email protected]>
commit 627f01eab93d8671d4e4afee9b148f9998d20e7c upstream.
One of the changes in Sphinx 5.0.0 [1] says [sic]:
5.0.0 final
- #10474: language does not accept None as it value. The default value of language becomes to 'en' now.
[1]: https://www.sphinx-doc.org/en/master/changes.html#release-5-0-0-released-may-30-2022
It results in a new warning from Sphinx 5.0.0 [sic]:
WARNING: Invalid configuration value found: 'language = None'. Update your configuration to a valid langauge code. Falling back to 'en' (English).
Silence the warning by using 'en'.
It works with all the Sphinx versions required for building kernel documentation (1.7.9 or later).
--- Documentation/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Documentation/conf.py +1 -1
@@ -161,7 +161,7 @@ finally: # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used:
Greg Kroah-Hartman
maintainerPATCH 644/667 dt-bindings: gpio: altera: correct interrupt-cells
In reply to Greg Kroah-HartmanFrom: Dinh Nguyen <[email protected]>
commit 3a21c3ac93aff7b4522b152399df8f6a041df56d upstream.
update documentation to correctly state the interrupt-cells to be 2.
--- Documentation/devicetree/bindings/gpio/gpio-altera.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
Documentation/devicetree/bindings/gpio/gpio-altera.txt +3 -2
@@ -9,8 +9,9 @@ Required properties: - The second cell is reserved and is currently unused. - gpio-controller : Marks the device node as a GPIO controller. - interrupt-controller: Mark the device node as an interrupt controller -- #interrupt-cells : Should be 1. The interrupt type is fixed in the hardware. +- #interrupt-cells : Should be 2. The interrupt type is fixed in the hardware. - The first cell is the GPIO offset number within the GPIO controller. + - The second cell is the interrupt trigger type and level flags. - interrupts: Specify the interrupt. - altr,interrupt-type: Specifies the interrupt trigger type the GPIO hardware is synthesized. This field is required if the Altera GPIO controller
@@ -38,6 +39,6 @@ gpio_altr: gpio@ff200000 { altr,interrupt-type = <IRQ_TYPE_EDGE_RISING>; #gpio-cells = <2>; gpio-controller; - #interrupt-cells = <1>; + #interrupt-cells = <2>; interrupt-controller; };
Greg Kroah-Hartman
maintainerPATCH 645/667 vdpasim: allow to enable a vq repeatedly
In reply to Greg Kroah-HartmanFrom: Eugenio Pérez <[email protected]>
commit 242436973831aa97e8ce19533c6c912ea8def31b upstream.
Code must be resilient to enable a queue many times.
At the moment the queue is resetting so it's definitely not the expected behavior.
v2: set vq->ready = 0 at disable.
Message-Id: <[email protected]>
--- drivers/vdpa/vdpa_sim/vdpa_sim.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/vdpa/vdpa_sim/vdpa_sim.c +4 -1
@@ -353,11 +353,14 @@ static void vdpasim_set_vq_ready(struct {struct vdpasim *vdpasim =vdpa_to_sim (vdpa);struct vdpasim_virtqueue *vq = &vdpasim->vqs[idx]; +bool old_ready;spin_lock (&vdpasim->lock); + old_ready = vq->ready; vq->ready = ready; -if (vq->ready) +if (vq->ready && !old_ready) {vdpasim_queue_ready (vdpasim, idx); + }spin_unlock (&vdpasim->lock); }
Greg Kroah-Hartman
maintainerPATCH 646/667 blk-iolatency: Fix inflight count imbalances and IO hangs on offline
In reply to Greg Kroah-HartmanFrom: Tejun Heo <[email protected]>
commit 8a177a36da6c54c98b8685d4f914cb3637d53c0d upstream.
iolatency needs to track the number of inflight IOs per cgroup. As this tracking can be expensive, it is disabled when no cgroup has iolatency configured for the device. To ensure that the inflight counters stay balanced, iolatency_set_limit() freezes the request_queue while manipulating the enabled counter, which ensures that no IO is in flight and thus all counters are zero.
Unfortunately, iolatency_set_limit() isn't the only place where the enabled counter is manipulated. iolatency_pd_offline() can also dec the counter and trigger disabling. As this disabling happens without freezing the q, this can easily happen while some IOs are in flight and thus leak the counts.
This can be easily demonstrated by turning on iolatency on an one empty cgroup while IOs are in flight in other cgroups and then removing the cgroup. Note that iolatency shouldn't have been enabled elsewhere in the system to ensure that removing the cgroup disables iolatency for the whole device.
The following keeps flipping on and off iolatency on sda:
echo +io > /sys/fs/cgroup/cgroup.subtree_control while true; do
mkdir -p /sys/fs/cgroup/test
echo '8:0 target=100000' > /sys/fs/cgroup/test/io.latency sleep 1
rmdir /sys/fs/cgroup/test
sleep 1
done
and there's concurrent fio generating direct rand reads:
fio --name test --filename=/dev/sda --direct=1 --rw=randread \
--runtime=600 --time_based --iodepth=256 --numjobs=4 --bs=4kwhile monitoring with the following drgn script:
while True:
for css in css_for_each_descendant_pre(prog['blkcg_root'].css.address_of_()):
for pos in hlist_for_each(container_of(css, 'struct blkcg', 'css').blkg_list):
blkg = container_of(pos, 'struct blkcg_gq', 'blkcg_node')
pd = blkg.pd[prog['blkcg_policy_iolatency'].plid]
if pd.value_() == 0:
continue
iolat = container_of(pd, 'struct iolatency_grp', 'pd') inflight = iolat.rq_wait.inflight.counter.value_()
if inflight:
print(f'inflight={inflight} {disk_name(blkg.q.disk).decode("utf-8")} '
f'{cgroup_path(css.cgroup).decode("utf-8")}')
time.sleep(1)
The monitoring output looks like the following:
inflight=1 sda /user.slice
inflight=1 sda /user.slice
...
inflight=14 sda /user.slice
inflight=13 sda /user.slice
inflight=17 sda /user.slice
inflight=15 sda /user.slice
inflight=18 sda /user.slice
inflight=17 sda /user.slice
inflight=20 sda /user.slice
inflight=19 sda /user.slice <- fio stopped, inflight stuck at 19 inflight=19 sda /user.slice
inflight=19 sda /user.slice
If a cgroup with stuck inflight ends up getting throttled, the throttled IOs will never get issued as there's no completion event to wake it up leading to an indefinite hang.
This patch fixes the bug by unifying enable handling into a work item which is automatically kicked off from iolatency_set_min_lat_nsec() which is called from both iolatency_set_limit() and iolatency_pd_offline() paths. Punting to a work item is necessary as iolatency_pd_offline() is called under spinlocks while freezing a request_queue requires a sleepable context.
This also simplifies the code reducing LOC sans the comments and avoids the unnecessary freezes which were happening whenever a cgroup's latency target is newly set or cleared.
--- block/blk-iolatency.c | 122 ++++++++++++++++++++++++++------------------------ 1 file changed, 64 insertions(+), 58 deletions(-)
block/blk-iolatency.c +64 -58
@@ -86,7 +86,17 @@ struct iolatency_grp;struct blk_iolatency {struct rq_qos rqos;struct timer_list timer; -atomic_t enabled; + +/* +* ->enabled is the master enable switch gating the throttling logic and +* inflight tracking. The number of cgroups which have iolat enabled is +* tracked in ->enable_cnt, and ->enable is flipped on/off accordingly +* from ->enable_work with the request_queue frozen. For details, See +* blkiolatency_enable_work_fn(). +*/ +bool enabled; +atomic_t enable_cnt; +struct work_struct enable_work; };static inline struct blk_iolatency *BLKIOLATENCY (struct rq_qos *rqos)
@@ -94,11 +104,6 @@ static inline struct blk_iolatency *BLKI return container_of(rqos, struct blk_iolatency, rqos); } -static inline bool blk_iolatency_enabled (struct blk_iolatency *blkiolat) -{ -return atomic_read (&blkiolat->enabled) >0 ; -} -struct child_latency_info {spinlock_t lock;
@@ -463,7 +468,7 @@ static void blkcg_iolatency_throttle(strstruct blkcg_gq *blkg = bio->bi_blkg;bool issue_as_root =bio_issue_as_root_blkg (bio); -if (!blk_iolatency_enabled (blkiolat)) +if (!blkiolat->enabled)return ;while (blkg && blkg->parent) {
@@ -593,7 +598,6 @@ static void blkcg_iolatency_done_bio(stru64 window_start;u64 now;bool issue_as_root =bio_issue_as_root_blkg (bio); -bool enabled = false;int inflight =0 ; blkg = bio->bi_blkg;
@@ -604,8 +608,7 @@ static void blkcg_iolatency_done_bio(strif (!iolat)return ; - enabled =blk_iolatency_enabled (iolat->blkiolat); -if (!enabled) +if (!iolat->blkiolat->enabled)return ; now =ktime_to_ns (ktime_get ());
@@ -644,6 +647,7 @@ static void blkcg_iolatency_exit(structstruct blk_iolatency *blkiolat =BLKIOLATENCY (rqos);del_timer_sync (&blkiolat->timer); +flush_work (&blkiolat->enable_work);blkcg_deactivate_policy (rqos->q, &blkcg_policy_iolatency);kfree (blkiolat); }
@@ -715,6 +719,44 @@ next:rcu_read_unlock (); } +/** +* blkiolatency_enable_work_fn - Enable or disable iolatency on the device +* @work: enable_work of the blk_iolatency of interest +* +* iolatency needs to keep track of the number of in-flight IOs per cgroup. This +* is relatively expensive as it involves walking up the hierarchy twice for +* every IO. Thus, if iolatency is not enabled in any cgroup for the device, we +* want to disable the in-flight tracking. +* +* We have to make sure that the counting is balanced - we don't want to leak +* the in-flight counts by disabling accounting in the completion path while IOs +* are in flight. This is achieved by ensuring that no IO is in flight by +* freezing the queue while flipping ->enabled. As this requires a sleepable +* context, ->enabled flipping is punted to this work function. +*/ +static void blkiolatency_enable_work_fn (struct work_struct *work) +{ + struct blk_iolatency *blkiolat = container_of(work, struct blk_iolatency, + enable_work); +bool enabled; + +/* +* There can only be one instance of this function running for @blkiolat +* and it's guaranteed to be executed at least once after the latest +* ->enabled_cnt modification. Acting on the latest ->enable_cnt is +* sufficient. +* +* Also, we know @blkiolat is safe to access as ->enable_work is flushed +* in blkcg_iolatency_exit(). +*/ + enabled =atomic_read (&blkiolat->enable_cnt); +if (enabled != blkiolat->enabled) { +blk_mq_freeze_queue (blkiolat->rqos.q); + blkiolat->enabled = enabled; +blk_mq_unfreeze_queue (blkiolat->rqos.q); + } +} +int blk_iolatency_init (struct request_queue *q) {struct blk_iolatency *blkiolat;
@@ -740,17 +782,15 @@ int blk_iolatency_init(struct request_qu }timer_setup (&blkiolat->timer, blkiolatency_timer_fn,0 ); +INIT_WORK (&blkiolat->enable_work, blkiolatency_enable_work_fn);return 0 ; } -/* -* return 1 for enabling iolatency, return -1 for disabling iolatency, otherwise -* return 0. -*/ -static int iolatency_set_min_lat_nsec (struct blkcg_gq *blkg,u64 val) +static void iolatency_set_min_lat_nsec (struct blkcg_gq *blkg,u64 val) {struct iolatency_grp *iolat =blkg_to_lat (blkg); +struct blk_iolatency *blkiolat = iolat->blkiolat;u64 oldval = iolat->min_lat_nsec; iolat->min_lat_nsec = val;
@@ -758,13 +798,15 @@ static int iolatency_set_min_lat_nsec(st iolat->cur_win_nsec =min_t (u64, iolat->cur_win_nsec,BLKIOLATENCY_MAX_WIN_SIZE ); -if (!oldval && val) -return 1 ; +if (!oldval && val) { +if (atomic_inc_return (&blkiolat->enable_cnt) ==1 ) +schedule_work (&blkiolat->enable_work); + }if (oldval && !val) {blkcg_clear_delay (blkg); -return -1 ; +if (atomic_dec_return (&blkiolat->enable_cnt) ==0 ) +schedule_work (&blkiolat->enable_work); } -return 0 ; }static void iolatency_clear_scaling (struct blkcg_gq *blkg)
@@ -796,7 +838,6 @@ static ssize_t iolatency_set_limit(strucu64 lat_val =0 ;u64 oldval;int ret; -int enable =0 ; ret =blkg_conf_prep (blkcg, &blkcg_policy_iolatency, buf, &ctx);if (ret)
@@ -831,41 +872,12 @@ static ssize_t iolatency_set_limit(struc blkg = ctx.blkg; oldval = iolat->min_lat_nsec; - enable =iolatency_set_min_lat_nsec (blkg, lat_val); -if (enable) { -if (!blk_get_queue (blkg->q)) { - ret = -ENODEV ; - goto out; - } - -blkg_get (blkg); - } - -if (oldval != iolat->min_lat_nsec) { +iolatency_set_min_lat_nsec (blkg, lat_val); +if (oldval != iolat->min_lat_nsec)iolatency_clear_scaling (blkg); - } - ret =0 ; out:blkg_conf_finish (&ctx); -if (ret ==0 && enable) { -struct iolatency_grp *tmp =blkg_to_lat (blkg); -struct blk_iolatency *blkiolat = tmp->blkiolat; - -blk_mq_freeze_queue (blkg->q); - -if (enable ==1 ) -atomic_inc (&blkiolat->enabled); -else if (enable ==-1 ) -atomic_dec (&blkiolat->enabled); -else -WARN_ON_ONCE (1 ); - -blk_mq_unfreeze_queue (blkg->q); - -blkg_put (blkg); -blk_put_queue (blkg->q); - }return ret ?: nbytes; }
@@ -1006,14 +1018,8 @@ static void iolatency_pd_offline(struct {struct iolatency_grp *iolat =pd_to_lat (pd);struct blkcg_gq *blkg =lat_to_blkg (iolat); -struct blk_iolatency *blkiolat = iolat->blkiolat; -int ret; - ret =iolatency_set_min_lat_nsec (blkg,0 ); -if (ret ==1 ) -atomic_inc (&blkiolat->enabled); -if (ret ==-1 ) -atomic_dec (&blkiolat->enabled); +iolatency_set_min_lat_nsec (blkg,0 );iolatency_clear_scaling (blkg); }
Greg Kroah-Hartman
maintainerPATCH 647/667 coresight: core: Fix coresight device probe failure issue
In reply to Greg Kroah-HartmanFrom: Mao Jinlong <[email protected]>
commit 8c1d3f79d9ca48e406b78e90e94cf09a8c076bf2 upstream.
It is possibe that probe failure issue happens when the device and its child_device's probe happens at the same time. In coresight_make_links, has_conns_grp is true for parent, but has_conns_grp is false for child device as has_conns_grp is set to true in coresight_create_conns_sysfs_group. The probe of parent device will fail at this condition. Add has_conns_grp check for child device before make the links and make the process from device_register to connection_create be atomic to avoid this probe failure issue.
--- drivers/hwtracing/coresight/coresight-core.c | 33 ++++++++++++++++++--------- 1 file changed, 22 insertions(+), 11 deletions(-)
drivers/hwtracing/coresight/coresight-core.c +22 -11
@@ -1382,7 +1382,7 @@ static int coresight_fixup_device_conns(continue ; conn->child_dev =coresight_find_csdev_by_fwnode (conn->child_fwnode); -if (conn->child_dev) { +if (conn->child_dev && conn->child_dev->has_conns_grp) { ret =coresight_make_links (csdev, conn, conn->child_dev);if (ret)
@@ -1574,6 +1574,7 @@ struct coresight_device *coresight_regisint nr_refcnts =1 ;atomic_t *refcnts =NULL ;struct coresight_device *csdev; +bool registered = false; csdev =kzalloc (sizeof (*csdev),GFP_KERNEL );if (!csdev) {
@@ -1594,7 +1595,8 @@ struct coresight_device *coresight_regis refcnts =kcalloc (nr_refcnts,sizeof (*refcnts),GFP_KERNEL );if (!refcnts) { ret = -ENOMEM ; - goto err_free_csdev; +kfree (csdev); + goto err_out; } csdev->refcnt = refcnts;
@@ -1619,6 +1621,13 @@ struct coresight_device *coresight_regis csdev->dev.fwnode =fwnode_handle_get (dev_fwnode (desc->dev));dev_set_name (&csdev->dev,"%s" , desc->name); +/* +* Make sure the device registration and the connection fixup +* are synchronised, so that we don't see uninitialised devices +* on the coresight bus while trying to resolve the connections. +*/ +mutex_lock (&coresight_mutex); + ret =device_register (&csdev->dev);if (ret) {put_device (&csdev->dev);
@@ -1626,7 +1635,7 @@ struct coresight_device *coresight_regis* All resources are free'd explicitly via * coresight_device_release(), triggered from put_device(). */ - goto err_out; + goto out_unlock; } if (csdev->type == CORESIGHT_DEV_TYPE_SINK ||
@@ -1641,11 +1650,11 @@ struct coresight_device *coresight_regis* from put_device(), which is in turn called from * function device_unregister(). */ - goto err_out; + goto out_unlock; } } - -mutex_lock (&coresight_mutex); +/* Device is now registered */ + registered = true; ret =coresight_create_conns_sysfs_group (csdev);if (!ret)
@@ -1655,16 +1664,18 @@ struct coresight_device *coresight_regisif (!ret && cti_assoc_ops && cti_assoc_ops->add) cti_assoc_ops->add (csdev); +out_unlock:mutex_unlock (&coresight_mutex); -if (ret) { +/* Success */ +if (!ret) +return csdev; + +/* Unregister the device if needed */ +if (registered) {coresight_unregister (csdev);return ERR_PTR (ret); } -return csdev; - -err_free_csdev: -kfree (csdev); err_out:/* Cleanup the connection information */ coresight_release_platform_data (NULL , desc->pdata);
Greg Kroah-Hartman
maintainerPATCH 648/667 phy: qcom-qmp: fix reset-controller leak on probe errors
In reply to Greg Kroah-HartmanFrom: Johan Hovold <[email protected]>
commit 4d2900f20edfe541f75756a00deeb2ffe7c66bc1 upstream.
Make sure to release the lane reset controller in case of a late probe error (e.g. probe deferral).
Note that due to the reset controller being defined in devicetree in "lane" child nodes, devm_reset_control_get_exclusive() cannot be used directly.
--- drivers/phy/qualcomm/phy-qcom-qmp.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/phy/qualcomm/phy-qcom-qmp.c +9 -0
@@ -5382,6 +5382,11 @@ static const struct phy_ops qcom_qmp_pci .owner = THIS_MODULE, }; +static void qcom_qmp_reset_control_put (void *data) +{ +reset_control_put (data); +} +static int qcom_qmp_phy_create (struct device *dev,struct device_node *np,int id,void __iomem *serdes,const struct qmp_phy_cfg *cfg)
@@ -5476,6 +5481,10 @@ int qcom_qmp_phy_create(struct device *ddev_err (dev,"failed to get lane%d reset\n" , id);return PTR_ERR (qphy->lane_rst); } + ret =devm_add_action_or_reset (dev, qcom_qmp_reset_control_put, + qphy->lane_rst); +if (ret) +return ret; }if (cfg->type ==PHY_TYPE_UFS || cfg->type ==PHY_TYPE_PCIE )
Greg Kroah-Hartman
maintainerPATCH 649/667 net: ipa: fix page free in ipa_endpoint_trans_release()
In reply to Greg Kroah-HartmanFrom: Alex Elder <[email protected]>
commit 155c0c90bca918de6e4327275dfc1d97fd604115 upstream.
Currently the (possibly compound) page used for receive buffers are freed using __free_pages(). But according to this comment above the definition of that function, that's wrong:
If you want to use the page's reference count to decide when to free the allocation, you should allocate a compound page, and use put_page() instead of __free_pages().
Convert the call to __free_pages() in ipa_endpoint_trans_release() to use put_page() instead.
--- drivers/net/ipa/ipa_endpoint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ipa/ipa_endpoint.c +1 -1
@@ -1389,7 +1389,7 @@ void ipa_endpoint_trans_release(struct istruct page *page = trans->data;if (page) -__free_pages (page,get_order (IPA_RX_BUFFER_SIZE )); +put_page (page); } }
Greg Kroah-Hartman
maintainerPATCH 650/667 net: ipa: fix page free in ipa_endpoint_replenish_one()
In reply to Greg Kroah-HartmanFrom: Alex Elder <[email protected]>
commit 70132763d5d2e94cd185e3aa92ac6a3ba89068fa upstream.
Currently the (possibly compound) pages used for receive buffers are freed using __free_pages(). But according to this comment above the definition of that function, that's wrong:
If you want to use the page's reference count to decide when to free the allocation, you should allocate a compound page, and use put_page() instead of __free_pages().
Convert the call to __free_pages() in ipa_endpoint_replenish_one() to use put_page() instead.
--- drivers/net/ipa/ipa_endpoint.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ipa/ipa_endpoint.c +1 -1
@@ -1049,7 +1049,7 @@ static int ipa_endpoint_replenish_one(st err_trans_free:gsi_trans_free (trans); err_free_pages: -__free_pages (page,get_order (IPA_RX_BUFFER_SIZE )); +put_page (page);return -ENOMEM ; }
Greg Kroah-Hartman
maintainerPATCH 651/667 kseltest/cgroup: Make test_stress.sh work if run interactively
In reply to Greg Kroah-HartmanFrom: Waiman Long <[email protected]>
commit 213adc63dfbcdff9a0c19ec1f2681fda9c05cf6d upstream.
Commit 54de76c01239 ("kselftest/cgroup: fix test_stress.sh to use OUTPUT dir") changes the test_core command path from . to $OUTPUT. However, variable OUTPUT may not be defined if the command is run interactively. Fix that by using ${OUTPUT:-.} to cover both cases.
--- tools/testing/selftests/cgroup/test_stress.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/cgroup/test_stress.sh +1 -1
@@ -1,4 +1,4 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 -./with_stress.sh -s subsys -s fork ${OUTPUT}/test_core +./with_stress.sh -s subsys -s fork ${OUTPUT:-.}/test_core
Greg Kroah-Hartman
maintainerPATCH 652/667 list: test: Add a test for list_is_head()
In reply to Greg Kroah-HartmanFrom: David Gow <[email protected]>
commit 37dc573c0a547e1aed0c9abb480fab797bd3833f upstream.
list_is_head() was added recently[1], and didn't have a KUnit test. The implementation is trivial, so it's not a particularly exciting test, but it'd be nice to get back to full coverage of the list functions.
--- lib/list-test.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
lib/list-test.c +19 -0
@@ -234,6 +234,24 @@ static void list_test_list_bulk_move_taiKUNIT_EXPECT_EQ (test, i,2 ); } +static void list_test_list_is_head (struct kunit *test) +{ +struct list_head a, b, c; + +/* Two lists: [a] -> b, [c] */ +INIT_LIST_HEAD (&a); +INIT_LIST_HEAD (&c); +list_add_tail (&b, &a); + +KUNIT_EXPECT_TRUE_MSG (test,list_is_head (&a, &a), +"Head element of same list" ); +KUNIT_EXPECT_FALSE_MSG (test,list_is_head (&a, &b), +"Non-head element of same list" ); +KUNIT_EXPECT_FALSE_MSG (test,list_is_head (&a, &c), +"Head element of different list" ); +} + +static void list_test_list_is_first (struct kunit *test) {struct list_head a, b;
@@ -710,6 +728,7 @@ static struct kunit_case list_test_casesKUNIT_CASE (list_test_list_move),KUNIT_CASE (list_test_list_move_tail),KUNIT_CASE (list_test_list_bulk_move_tail), +KUNIT_CASE (list_test_list_is_head),KUNIT_CASE (list_test_list_is_first),KUNIT_CASE (list_test_list_is_last), KUNIT_CASE(list_test_list_empty),
Greg Kroah-Hartman
maintainerPATCH 653/667 Revert "random: use static branch for crng_ready()"
In reply to Greg Kroah-HartmanFrom: "Jason A. Donenfeld" <[email protected]>
This reverts upstream commit f5bda35fba615ace70a656d4700423fa6c9bebee from stable. It's not essential and will take some time during 5.19 to work out properly.
--- drivers/char/random.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-)
drivers/char/random.c +2 -10
@@ -79,8 +79,7 @@ static enum {CRNG_EARLY =1 ,/* At least POOL_EARLY_BITS collected */ CRNG_READY = 2 /* Fully initialized with POOL_READY_BITS collected */ } crng_init__read_mostly =CRNG_EMPTY ; -static DEFINE_STATIC_KEY_FALSE (crng_is_ready); -#define crng_ready () (static_branch_likely(&crng_is_ready) || crng_init >= CRNG_READY) +#define crng_ready () (likely(crng_init >= CRNG_READY))/* Various types of waiters for crng_init->CRNG_READY transition. */ static DECLARE_WAIT_QUEUE_HEAD (crng_init_wait);static struct fasync_struct *fasync;
@@ -110,11 +109,6 @@ bool rng_is_initialized(void) }EXPORT_SYMBOL (rng_is_initialized); -static void __cold crng_set_ready (struct work_struct *work) -{ -static_branch_enable (&crng_is_ready); -} -/* Used by wait_for_random_bytes(), and considered an entropy collector, below. */ static void try_to_generate_entropy (void );
@@ -268,7 +262,7 @@ static void crng_reseed(void) ++next_gen;WRITE_ONCE (base_crng.generation, next_gen);WRITE_ONCE (base_crng.birth, jiffies); -if (!static_branch_likely (&crng_is_ready)) +if (!crng_ready ()) crng_init =CRNG_READY ;spin_unlock_irqrestore (&base_crng.lock, flags);memzero_explicit (key,sizeof (key));
@@ -711,7 +705,6 @@ static void extract_entropy(void *buf, sstatic void __cold _credit_init_bits (size_t bits) { -static struct execute_work set_ready;unsigned int new, orig, add;unsigned long flags;
@@ -727,7 +720,6 @@ static void __cold _credit_init_bits(sizif (orig <POOL_READY_BITS && new >=POOL_READY_BITS ) {crng_reseed ();/* Sets crng_init to CRNG_READY under base_crng.lock. */ -execute_in_process_context (crng_set_ready, &set_ready);process_random_ready_list ();wake_up_interruptible (&crng_init_wait);kill_fasync (&fasync,SIGIO ,POLL_IN );
Greg Kroah-Hartman
maintainerPATCH 654/667 staging: r8188eu: delete rtw_wx_read/write32()
In reply to Greg Kroah-HartmanFrom: Dan Carpenter <[email protected]>
commit 4d0cc9e0e53e9946d7b8dc58279c62dfa7a2191b upstream.
These debugging tools let you call:
status = usb_control_msg_recv/send(udev, 0, REALTEK_USB_VENQT_CMD_REQ, REALTEK_USB_VENQT_READ/WRITE, value, REALTEK_USB_VENQT_CMD_IDX, io_buf, size, RTW_USB_CONTROL_MSG_TIMEOUT, GFP_KERNEL);
with a user controlled "value" in the 0-0xffff range. It's not a valid API.
--- drivers/staging/r8188eu/os_dep/ioctl_linux.c | 97 --------------------------- 1 file changed, 2 insertions(+), 95 deletions(-)
drivers/staging/r8188eu/os_dep/ioctl_linux.c +2 -95
@@ -2052,99 +2052,6 @@ static int rtw_wx_get_nick(struct net_dereturn 0 ; } -static int rtw_wx_read32 (struct net_device *dev, -struct iw_request_info *info, -union iwreq_data *wrqu,char *extra) -{ -struct adapter *padapter; -struct iw_point *p; -u16 len; -u32 addr; -u32 data32; -u32 bytes; -u8 *ptmp; -int ret; - - padapter = (struct adapter *)rtw_netdev_priv (dev); - p = &wrqu->data; - len = p->length; - ptmp =kmalloc (len,GFP_KERNEL ); -if (!ptmp) -return -ENOMEM ; - -if (copy_from_user (ptmp, p->pointer, len)) { -kfree (ptmp); -return -EFAULT ; - } - - bytes =0 ; - addr =0 ; -sscanf (ptmp,"%d,%x" , &bytes, &addr); - -switch (bytes) { -case 1 : - data32 =rtw_read8 (padapter, addr); -sprintf (extra,"0x%02X" , data32); -break ; -case 2 : - data32 =rtw_read16 (padapter, addr); -sprintf (extra,"0x%04X" , data32); -break ; -case 4 : - data32 =rtw_read32 (padapter, addr); -sprintf (extra,"0x%08X" , data32); -break ; -default : -DBG_88E (KERN_INFO "%s: usage> read [bytes],[address(hex)]\n" , __func__); - ret = -EINVAL ; - goto err_free_ptmp; - } -DBG_88E (KERN_INFO "%s: addr = 0x%08X data =%s\n" , __func__, addr, extra); - -kfree (ptmp); -return 0 ; - -err_free_ptmp: -kfree (ptmp); -return ret; -} - -static int rtw_wx_write32 (struct net_device *dev, -struct iw_request_info *info, -union iwreq_data *wrqu,char *extra) -{ -struct adapter *padapter = (struct adapter *)rtw_netdev_priv (dev); - -u32 addr; -u32 data32; -u32 bytes; - - bytes =0 ; - addr =0 ; - data32 =0 ; -sscanf (extra,"%d,%x,%x" , &bytes, &addr, &data32); - -switch (bytes) { -case 1 : -rtw_write8 (padapter, addr, (u8 )data32); -DBG_88E (KERN_INFO "%s: addr = 0x%08X data = 0x%02X\n" , __func__, addr, (u8 )data32); -break ; -case 2 : -rtw_write16 (padapter, addr, (u16 )data32); -DBG_88E (KERN_INFO "%s: addr = 0x%08X data = 0x%04X\n" , __func__, addr, (u16 )data32); -break ; -case 4 : -rtw_write32 (padapter, addr, data32); -DBG_88E (KERN_INFO "%s: addr = 0x%08X data = 0x%08X\n" , __func__, addr, data32); -break ; -default : -DBG_88E (KERN_INFO "%s: usage> write [bytes],[address(hex)],[data(hex)]\n" , __func__); -return -EINVAL ; - } - -return 0 ; -} -static int rtw_wx_read_rf (struct net_device *dev,struct iw_request_info *info,union iwreq_data *wrqu,char *extra)
@@ -6579,8 +6486,8 @@ static const struct iw_priv_args rtw_pri };static iw_handler rtw_private_handler[] = { -rtw_wx_write32,/* 0x00 */ -rtw_wx_read32,/* 0x01 */ +NULL ,/* 0x00 */ +NULL ,/* 0x01 */ rtw_drvext_hdl,/* 0x02 */ rtw_mp_ioctl_hdl,/* 0x03 */
Greg Kroah-Hartman
maintainerPATCH 655/667 RDMA/hns: Remove the num_cqc_timer variable
In reply to Greg Kroah-HartmanFrom: Yixing Liu <[email protected]>
commit db5dfbf5b201df65c1f5332c4d9d5e7c2f42396b upstream.
The bt number of cqc_timer of HIP09 increases compared with that of HIP08. Therefore, cqc_timer_bt_num and num_cqc_timer do not match. As a result, the driver may fail to allocate cqc_timer. So the driver needs to uniquely uses cqc_timer_bt_num to represent the bt number of cqc_timer.
--- drivers/infiniband/hw/hns/hns_roce_device.h | 1 - drivers/infiniband/hw/hns/hns_roce_hw_v2.c | 3 +-- drivers/infiniband/hw/hns/hns_roce_hw_v2.h | 2 +- drivers/infiniband/hw/hns/hns_roce_main.c | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-)
drivers/infiniband/hw/hns/hns_roce_device.h +0 -1
@@ -759,7 +759,6 @@ struct hns_roce_caps {u32 num_pi_qps;u32 reserved_qps;int num_qpc_timer; -int num_cqc_timer;int num_srqs;u32 max_wqes;u32 max_srq_wrs;
drivers/infiniband/hw/hns/hns_roce_hw_v2.c +1 -2
@@ -1973,7 +1973,7 @@ static void set_default_caps(struct hns_ caps->num_mtpts =HNS_ROCE_V2_MAX_MTPT_NUM ; caps->num_pds =HNS_ROCE_V2_MAX_PD_NUM ; caps->num_qpc_timer =HNS_ROCE_V2_MAX_QPC_TIMER_NUM ; - caps->num_cqc_timer =HNS_ROCE_V2_MAX_CQC_TIMER_NUM ; + caps->cqc_timer_bt_num =HNS_ROCE_V2_MAX_CQC_TIMER_BT_NUM ; caps->max_qp_init_rdma =HNS_ROCE_V2_MAX_QP_INIT_RDMA ; caps->max_qp_dest_rdma =HNS_ROCE_V2_MAX_QP_DEST_RDMA ;
@@ -2267,7 +2267,6 @@ static int hns_roce_query_pf_caps(struct caps->max_rq_sg =roundup_pow_of_two (caps->max_rq_sg); caps->max_extend_sg =le32_to_cpu (resp_a->max_extend_sg); caps->num_qpc_timer =le16_to_cpu (resp_a->num_qpc_timer); - caps->num_cqc_timer =le16_to_cpu (resp_a->num_cqc_timer); caps->max_srq_sges =le16_to_cpu (resp_a->max_srq_sges); caps->max_srq_sges =roundup_pow_of_two (caps->max_srq_sges); caps->num_aeq_vectors = resp_a->num_aeq_vectors;
drivers/infiniband/hw/hns/hns_roce_hw_v2.h +1 -1
@@ -51,7 +51,7 @@#define HNS_ROCE_V2_MAX_SRQ_WR 0x8000#define HNS_ROCE_V2_MAX_SRQ_SGE 64#define HNS_ROCE_V2_MAX_CQ_NUM 0x100000 -#define HNS_ROCE_V2_MAX_CQC_TIMER_NUM 0x100 +#define HNS_ROCE_V2_MAX_CQC_TIMER_BT_NUM 0x100#define HNS_ROCE_V2_MAX_SRQ_NUM 0x100000#define HNS_ROCE_V2_MAX_CQE_NUM 0x400000#define HNS_ROCE_V2_MAX_SRQWQE_NUM 0x8000
drivers/infiniband/hw/hns/hns_roce_main.c +1 -1
@@ -663,7 +663,7 @@ static int hns_roce_init_hem(struct hns_ ret =hns_roce_init_hem_table (hr_dev, &hr_dev->cqc_timer_table,HEM_TYPE_CQC_TIMER , hr_dev->caps.cqc_timer_entry_sz, - hr_dev->caps.num_cqc_timer,1 ); + hr_dev->caps.cqc_timer_bt_num,1 );if (ret) {dev_err (dev,"Failed to init CQC timer memory, aborting.\n" );
Greg Kroah-Hartman
maintainerPATCH 656/667 RDMA/rxe: Generate a completion for unsupported/invalid opcode
In reply to Greg Kroah-HartmanFrom: Xiao Yang <[email protected]>
commit 2f917af777011c88e977b9b9a5d00b280d3a59ce upstream.
Current rxe_requester() doesn't generate a completion when processing an unsupported/invalid opcode. If rxe driver doesn't support a new opcode (e.g. RDMA Atomic Write) and RDMA library supports it, an application using the new opcode can reproduce this issue. Fix the issue by calling "goto err;".
--- drivers/infiniband/sw/rxe/rxe_req.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/sw/rxe/rxe_req.c +1 -1
@@ -683,7 +683,7 @@ next_wqe: opcode =next_opcode (qp, wqe, wqe->wr.opcode);if (unlikely (opcode <0 )) { wqe->status =IB_WC_LOC_QP_OP_ERR ; - goto exit; + goto err; } mask = rxe_opcode[opcode].mask;
Greg Kroah-Hartman
maintainerPATCH 657/667 MIPS: IP27: Remove incorrect `cpu_has_fpu override
In reply to Greg Kroah-HartmanFrom: Maciej W. Rozycki <[email protected]>
commit 424c3781dd1cb401857585331eaaa425a13f2429 upstream.
Remove unsupported forcing of cpu_has_fpu' to 1, which makes the nofpu' kernel parameter non-functional, and also causes a link error:
ld: arch/mips/kernel/traps.o: in function `trap_init':
./arch/mips/include/asm/msa.h:(.init.text+0x348): undefined reference to `handle_fpe'
ld: ./arch/mips/include/asm/msa.h:(.init.text+0x354): undefined reference to `handle_fpe'
ld: ./arch/mips/include/asm/msa.h:(.init.text+0x360): undefined reference to `handle_fpe'
where the CONFIG_MIPS_FP_SUPPORT configuration option has been disabled.
--- arch/mips/include/asm/mach-ip27/cpu-feature-overrides.h | 1 - 1 file changed, 1 deletion(-)
arch/mips/include/asm/mach-ip27/cpu-feature-overrides.h +0 -1
@@ -26,7 +26,6 @@#define cpu_has_3k_cache 0#define cpu_has_4k_cache 1#define cpu_has_tx39_cache 0 -#define cpu_has_fpu 1#define cpu_has_nofpuex 0#define cpu_has_32fpr 1#define cpu_has_counter 1
Greg Kroah-Hartman
maintainerPATCH 658/667 MIPS: IP30: Remove incorrect `cpu_has_fpu override
In reply to Greg Kroah-HartmanFrom: Maciej W. Rozycki <[email protected]>
commit f44b3e74c33fe04defeff24ebcae98c3bcc5b285 upstream.
Remove unsupported forcing of cpu_has_fpu' to 1, which makes the nofpu' kernel parameter non-functional, and also causes a link error:
ld: arch/mips/kernel/traps.o: in function `trap_init':
./arch/mips/include/asm/msa.h:(.init.text+0x348): undefined reference to `handle_fpe'
ld: ./arch/mips/include/asm/msa.h:(.init.text+0x354): undefined reference to `handle_fpe'
ld: ./arch/mips/include/asm/msa.h:(.init.text+0x360): undefined reference to `handle_fpe'
where the CONFIG_MIPS_FP_SUPPORT configuration option has been disabled.
--- arch/mips/include/asm/mach-ip30/cpu-feature-overrides.h | 1 - 1 file changed, 1 deletion(-)
arch/mips/include/asm/mach-ip30/cpu-feature-overrides.h +0 -1
@@ -29,7 +29,6 @@#define cpu_has_3k_cache 0#define cpu_has_4k_cache 1#define cpu_has_tx39_cache 0 -#define cpu_has_fpu 1#define cpu_has_nofpuex 0#define cpu_has_32fpr 1#define cpu_has_counter 1
Greg Kroah-Hartman
maintainerPATCH 659/667 ext4: only allow test_dummy_encryption when supported
In reply to Greg Kroah-HartmanFrom: Eric Biggers <[email protected]>
commit 5f41fdaea63ddf96d921ab36b2af4a90ccdb5744 upstream.
Make the test_dummy_encryption mount option require that the encrypt feature flag be already enabled on the filesystem, rather than automatically enabling it. Practically, this means that "-O encrypt" will need to be included in MKFS_OPTIONS when running xfstests with the test_dummy_encryption mount option. (ext4/053 also needs an update.)
Moreover, as long as the preconditions for test_dummy_encryption are being tightened anyway, take the opportunity to start rejecting it when !CONFIG_FS_ENCRYPTION rather than ignoring it.
The motivation for requiring the encrypt feature flag is that:
- Having the filesystem auto-enable feature flags is problematic, as it bypasses the usual sanity checks. The specific issue which came up recently is that in kernel versions where ext4 supports casefold but not encrypt+casefold (v5.1 through v5.10), the kernel will happily add the encrypt flag to a filesystem that has the casefold flag, making it unmountable -- but only for subsequent mounts, not the initial one. This confused the casefold support detection in xfstests, causing generic/556 to fail rather than be skipped.
- The xfstests-bld test runners (kvm-xfstests et al.) already use the required mkfs flag, so they will not be affected by this change. Only users of test_dummy_encryption alone will be affected. But, this option has always been for testing only, so it should be fine to require that the few users of this option update their test scripts.
- f2fs already requires it (for its equivalent feature flag).
--- fs/ext4/ext4.h | 6 ------ fs/ext4/super.c | 18 ++++++++++-------- 2 files changed, 10 insertions(+), 14 deletions(-)
fs/ext4/ext4.h +0 -6
@@ -1435,12 +1435,6 @@ struct ext4_super_block {#ifdef __KERNEL__ -#ifdef CONFIG_FS_ENCRYPTION -#define DUMMY_ENCRYPTION_ENABLED (sbi) ((sbi)->s_dummy_enc_policy.policy != NULL) -#else -#define DUMMY_ENCRYPTION_ENABLED (sbi) (0) -#endif -/* Number of quota types we support */ #define EXT4_MAXQUOTAS 3
fs/ext4/super.c +10 -8
@@ -2059,6 +2059,12 @@ static int ext4_set_test_dummy_encryptiostruct ext4_sb_info *sbi =EXT4_SB (sb);int err; +if (!ext4_has_feature_encrypt (sb)) { +ext4_msg (sb,KERN_WARNING , +"test_dummy_encryption requires encrypt feature" ); +return -1 ; + } +/* * This mount option is just for testing, and it's not worthwhile to * implement the extra complexity (e.g. RCU protection) that would be
@@ -2086,11 +2092,13 @@ static int ext4_set_test_dummy_encryptioreturn -1 ; }ext4_msg (sb,KERN_WARNING ,"Test dummy encryption mode enabled" ); +return 1 ;#else ext4_msg (sb,KERN_WARNING , -"Test dummy encryption mount option ignored" ); +"test_dummy_encryption option not supported" ); +return -1 ; +#endif -return 1 ; } struct ext4_parsed_options {
@@ -4784,12 +4792,6 @@ no_journal: goto failed_mount_wq; } -if (DUMMY_ENCRYPTION_ENABLED (sbi) && !sb_rdonly (sb) && - !ext4_has_feature_encrypt (sb)) { -ext4_set_feature_encrypt (sb); -ext4_commit_super (sb); - } -/* * Get the # of file system overhead blocks from the * superblock if present.
Greg Kroah-Hartman
maintainerPATCH 660/667 interconnect: qcom: sc7180: Drop IP0 interconnects
In reply to Greg Kroah-HartmanFrom: Stephen Boyd <[email protected]>
commit 2f3724930eb4bba74f7d10bc3bef5bb22dd323df upstream.
The IPA BCM resource ("IP0") on sc7180 was moved to the clk-rpmh driver in commit bcd63d222b60 ("clk: qcom: rpmh: Add IPA clock for SC7180") and modeled as a clk, but this interconnect driver still had it modeled as an interconnect. This was mostly OK because nobody used the interconnect definition, until the interconnect framework started dropping bandwidth requests on interconnects that aren't used via the sync_state callback in commit 7d3b0b0d8184 ("interconnect: qcom: Use icc_sync_state"). Once that patch was applied the IP0 resource was going to be controlled from two places, the clk framework and the interconnect framework.
Even then, things were probably going to be OK, because commit b95b668eaaa2 ("interconnect: qcom: icc-rpmh: Add BCMs to commit list in pre_aggregate") was needed to actually drop bandwidth requests on unused interconnects, of which the IPA was one of the interconnect that wasn't getting dropped to zero. Combining the three commits together leads to bad behavior where the interconnect framework is disabling the IP0 resource because it has no users while the clk framework thinks the IP0 resource is on because the only user, the IPA driver, has turned it on via clk_prepare_enable(). Depending on when sync_state is called, we can get into a situation like below:
IPA driver probes
IPA driver gets notified modem started
runtime PM get()
IPA clk enabled -> IP0 resource is ON
sync_state runs
interconnect zeroes out the IP0 resource -> IP0 resource is off
IPA driver tries to access a register and blows up
The crash is an unclocked access that manifest as an SError.
SError Interrupt on CPU0, code 0xbe000011 -- SError
CPU: 0 PID: 3595 Comm: mmdata_mgr Not tainted 5.17.1+ #166 Hardware name: Google Lazor (rev1 - 2) with LTE (DT) pstate: 60400009 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--) pc : mutex_lock+0x4c/0x80 lr : mutex_lock+0x30/0x80 sp : ffffffc00da9b9c0 x29: ffffffc00da9b9c0 x28: 0000000000000000 x27: 0000000000000000 x26: ffffffc00da9bc90 x25: ffffff80c2024010 x24: ffffff80c2024000 x23: ffffff8083100000 x22: ffffff80831000d0 x21: ffffff80831000a8 x20: ffffff80831000a8 x19: ffffff8083100070 x18: 00000000ffff0a00 x17: 000000002f7254f1 x16: 0000000000000100 x15: 0000000000000000 x14: 0000000000000000 x13: 0000000000000000 x12: 0000000000000000 x11: 000000000001f0b8 x10: ffffffc00931f0b8 x9 : 0000000000000000 x8 : 0000000000000000 x7 : fefefefefeff2f60 x6 : 0000808080808080 x5 : 0000000000000000 x4 : 8080808080800000 x3 : ffffff80d2d4ee28 x2 : ffffff808c1d6e40 x1 : 0000000000000000 x0 : ffffff8083100070 Kernel panic - not syncing: Asynchronous SError Interrupt CPU: 0 PID: 3595 Comm: mmdata_mgr Not tainted 5.17.1+ #166 Hardware name: Google Lazor (rev1 - 2) with LTE (DT) Call trace: dump_backtrace+0xf4/0x114 show_stack+0x24/0x30 dump_stack_lvl+0x64/0x7c dump_stack+0x18/0x38 panic+0x150/0x38c nmi_panic+0x88/0xa0 arm64_serror_panic+0x74/0x80 do_serror+0x0/0x80 do_serror+0x58/0x80 el1h_64_error_handler+0x34/0x4c el1h_64_error+0x78/0x7c mutex_lock+0x4c/0x80 __gsi_channel_start+0x50/0x17c gsi_channel_start+0x54/0x90 ipa_endpoint_enable_one+0x34/0xc0 ipa_open+0x4c/0x120
Remove all IP0 resource management from the interconnect driver so that clk-rpmh is the sole owner. This fixes the issue by preventing the interconnect driver from overwriting the IP0 resource data that the clk-rpmh driver wrote.
--- drivers/interconnect/qcom/sc7180.c | 21 --------------------- 1 file changed, 21 deletions(-)
drivers/interconnect/qcom/sc7180.c +0 -21
@@ -47,7 +47,6 @@ DEFINE_QNODE(qnm_mnoc_sf, SC7180_MASTER_DEFINE_QNODE (qnm_snoc_gc,SC7180_MASTER_SNOC_GC_MEM_NOC ,1 ,8 ,SC7180_SLAVE_LLCC );DEFINE_QNODE (qnm_snoc_sf,SC7180_MASTER_SNOC_SF_MEM_NOC ,1 ,16 ,SC7180_SLAVE_LLCC );DEFINE_QNODE (qxm_gpu,SC7180_MASTER_GFX3D ,2 ,32 ,SC7180_SLAVE_GEM_NOC_SNOC ,SC7180_SLAVE_LLCC ); -DEFINE_QNODE (ipa_core_master,SC7180_MASTER_IPA_CORE ,1 ,8 ,SC7180_SLAVE_IPA_CORE );DEFINE_QNODE (llcc_mc,SC7180_MASTER_LLCC ,2 ,4 ,SC7180_SLAVE_EBI1 );DEFINE_QNODE (qhm_mnoc_cfg,SC7180_MASTER_CNOC_MNOC_CFG ,1 ,4 ,SC7180_SLAVE_SERVICE_MNOC );DEFINE_QNODE (qxm_camnoc_hf0,SC7180_MASTER_CAMNOC_HF0 ,2 ,32 ,SC7180_SLAVE_MNOC_HF_MEM_NOC );
@@ -129,7 +128,6 @@ DEFINE_QNODE(qhs_mdsp_ms_mpu_cfg, SC7180DEFINE_QNODE (qns_gem_noc_snoc,SC7180_SLAVE_GEM_NOC_SNOC ,1 ,8 ,SC7180_MASTER_GEM_NOC_SNOC );DEFINE_QNODE (qns_llcc,SC7180_SLAVE_LLCC ,1 ,16 ,SC7180_MASTER_LLCC );DEFINE_QNODE (srvc_gemnoc,SC7180_SLAVE_SERVICE_GEM_NOC ,1 ,4 ); -DEFINE_QNODE (ipa_core_slave,SC7180_SLAVE_IPA_CORE ,1 ,8 );DEFINE_QNODE (ebi,SC7180_SLAVE_EBI1 ,2 ,4 );DEFINE_QNODE (qns_mem_noc_hf,SC7180_SLAVE_MNOC_HF_MEM_NOC ,1 ,32 ,SC7180_MASTER_MNOC_HF_MEM_NOC );DEFINE_QNODE (qns_mem_noc_sf,SC7180_SLAVE_MNOC_SF_MEM_NOC ,1 ,32 ,SC7180_MASTER_MNOC_SF_MEM_NOC );
@@ -160,7 +158,6 @@ DEFINE_QBCM(bcm_mc0, "MC0", true, &ebi);DEFINE_QBCM (bcm_sh0,"SH0" , true, &qns_llcc);DEFINE_QBCM (bcm_mm0,"MM0" , false, &qns_mem_noc_hf);DEFINE_QBCM (bcm_ce0,"CE0" , false, &qxm_crypto); -DEFINE_QBCM (bcm_ip0,"IP0" , false, &ipa_core_slave);DEFINE_QBCM (bcm_cn0,"CN0" , true, &qnm_snoc, &xm_qdss_dap, &qhs_a1_noc_cfg, &qhs_a2_noc_cfg, &qhs_ahb2phy0, &qhs_aop, &qhs_aoss, &qhs_boot_rom, &qhs_camera_cfg, &qhs_camera_nrt_throttle_cfg, &qhs_camera_rt_throttle_cfg, &qhs_clk_ctl, &qhs_cpr_cx, &qhs_cpr_mx, &qhs_crypto0_cfg, &qhs_dcc_cfg, &qhs_ddrss_cfg, &qhs_display_cfg, &qhs_display_rt_throttle_cfg, &qhs_display_throttle_cfg, &qhs_glm, &qhs_gpuss_cfg, &qhs_imem_cfg, &qhs_ipa, &qhs_mnoc_cfg, &qhs_mss_cfg, &qhs_npu_cfg, &qhs_npu_dma_throttle_cfg, &qhs_npu_dsp_throttle_cfg, &qhs_pimem_cfg, &qhs_prng, &qhs_qdss_cfg, &qhs_qm_cfg, &qhs_qm_mpu_cfg, &qhs_qup0, &qhs_qup1, &qhs_security, &qhs_snoc_cfg, &qhs_tcsr, &qhs_tlmm_1, &qhs_tlmm_2, &qhs_tlmm_3, &qhs_ufs_mem_cfg, &qhs_usb3, &qhs_venus_cfg, &qhs_venus_throttle_cfg, &qhs_vsense_ctrl_cfg, &srvc_cnoc);DEFINE_QBCM (bcm_mm1,"MM1" , false, &qxm_camnoc_hf0_uncomp, &qxm_camnoc_hf1_uncomp, &qxm_camnoc_sf_uncomp, &qhm_mnoc_cfg, &qxm_mdp0, &qxm_rot, &qxm_venus0, &qxm_venus_arm9);DEFINE_QBCM (bcm_sh2,"SH2" , false, &acm_sys_tcu);
@@ -372,22 +369,6 @@ static struct qcom_icc_desc sc7180_gem_n .num_bcms = ARRAY_SIZE(gem_noc_bcms), }; -static struct qcom_icc_bcm *ipa_virt_bcms[] = { - &bcm_ip0, -}; - -static struct qcom_icc_node *ipa_virt_nodes[] = { - [MASTER_IPA_CORE ] = &ipa_core_master, - [SLAVE_IPA_CORE ] = &ipa_core_slave, -}; - -static struct qcom_icc_desc sc7180_ipa_virt = { - .nodes = ipa_virt_nodes, - .num_nodes =ARRAY_SIZE (ipa_virt_nodes), - .bcms = ipa_virt_bcms, - .num_bcms =ARRAY_SIZE (ipa_virt_bcms), -}; -static struct qcom_icc_bcm *mc_virt_bcms[] = { &bcm_acv, &bcm_mc0,
@@ -519,8 +500,6 @@ static const struct of_device_id qnoc_of .data = &sc7180_dc_noc}, { .compatible = "qcom,sc7180-gem-noc", .data = &sc7180_gem_noc}, - { .compatible = "qcom,sc7180-ipa-virt", - .data = &sc7180_ipa_virt}, { .compatible = "qcom,sc7180-mc-virt", .data = &sc7180_mc_virt}, { .compatible = "qcom,sc7180-mmss-noc",
Greg Kroah-Hartman
maintainerPATCH 661/667 interconnect: qcom: icc-rpmh: Add BCMs to commit list in pre_aggregate
In reply to Greg Kroah-HartmanFrom: Mike Tipton <[email protected]>
commit b95b668eaaa2574e8ee72f143c52075e9955177e upstream.
We're only adding BCMs to the commit list in aggregate(), but there are cases where pre_aggregate() is called without subsequently calling aggregate(). In particular, in icc_sync_state() when a node with initial BW has zero requests. Since BCMs aren't added to the commit list in these cases, we don't actually send the zero BW request to HW. So the resources remain on unnecessarily.
Add BCMs to the commit list in pre_aggregate() instead, which is always called even when there are no requests.
--- drivers/interconnect/qcom/icc-rpmh.c | 10 +++++----- drivers/interconnect/qcom/sm8150.c | 1 - drivers/interconnect/qcom/sm8250.c | 1 - drivers/interconnect/qcom/sm8350.c | 1 - 4 files changed, 5 insertions(+), 8 deletions(-)
drivers/interconnect/qcom/icc-rpmh.c +5 -5
@@ -21,13 +21,18 @@ void qcom_icc_pre_aggregate(struct icc_n {size_t i;struct qcom_icc_node *qn; +struct qcom_icc_provider *qp; qn = node->data; + qp =to_qcom_provider (node->provider);for (i =0 ; i <QCOM_ICC_NUM_BUCKETS ; i++) { qn->sum_avg[i] =0 ; qn->max_peak[i] =0 ; } + +for (i =0 ; i < qn->num_bcms; i++) +qcom_icc_bcm_voter_add (qp->voter, qn->bcms[i]); }EXPORT_SYMBOL_GPL (qcom_icc_pre_aggregate);
@@ -45,10 +50,8 @@ int qcom_icc_aggregate(struct icc_node * {size_t i;struct qcom_icc_node *qn; -struct qcom_icc_provider *qp; qn = node->data; - qp =to_qcom_provider (node->provider);if (!tag) tag =QCOM_ICC_TAG_ALWAYS ;
@@ -68,9 +71,6 @@ int qcom_icc_aggregate(struct icc_node * *agg_avg += avg_bw; *agg_peak =max_t (u32, *agg_peak, peak_bw); -for (i =0 ; i < qn->num_bcms; i++) -qcom_icc_bcm_voter_add (qp->voter, qn->bcms[i]); -return 0 ; }EXPORT_SYMBOL_GPL (qcom_icc_aggregate);
drivers/interconnect/qcom/sm8150.c +0 -1
@@ -535,7 +535,6 @@ static struct platform_driver qnoc_drive .driver = { .name = "qnoc-sm8150", .of_match_table = qnoc_of_match, - .sync_state = icc_sync_state, }, };module_platform_driver (qnoc_driver);
drivers/interconnect/qcom/sm8250.c +0 -1
@@ -551,7 +551,6 @@ static struct platform_driver qnoc_drive .driver = { .name = "qnoc-sm8250", .of_match_table = qnoc_of_match, - .sync_state = icc_sync_state, }, };module_platform_driver (qnoc_driver);
drivers/interconnect/qcom/sm8350.c +0 -1
@@ -531,7 +531,6 @@ static struct platform_driver qnoc_drive .driver = { .name = "qnoc-sm8350", .of_match_table = qnoc_of_match, - .sync_state = icc_sync_state, }, };module_platform_driver (qnoc_driver);
Greg Kroah-Hartman
maintainerPATCH 662/667 fs: add two trivial lookup helpers
In reply to Greg Kroah-HartmanFrom: Christian Brauner <[email protected]>
commit 00675017e0aeba5305665c52ded4ddce6a4c0231 upstream.
Similar to the addition of lookup_one() add a version of lookup_one_unlocked() and lookup_one_positive_unlocked() that take idmapped mounts into account. This is required to port overlay to support idmapped base layers.
--- fs/namei.c | 70 ++++++++++++++++++++++++++++++++++++++++++-------- include/linux/namei.h | 6 ++++ 2 files changed, 66 insertions(+), 10 deletions(-)
fs/namei.c +60 -10
@@ -2718,7 +2718,8 @@ struct dentry *lookup_one(struct user_naEXPORT_SYMBOL (lookup_one);/** -* lookup_one_len_unlocked - filesystem helper to lookup single pathname component +* lookup_one_unlocked - filesystem helper to lookup single pathname component +* @mnt_userns: idmapping of the mount the lookup is performed from * @name: pathname component to lookup * @base: base directory to lookup from * @len: maximum length @len should be interpreted to
@@ -2729,14 +2730,15 @@ EXPORT_SYMBOL(lookup_one);* Unlike lookup_one_len, it should be called without the parent * i_mutex held, and will take the i_mutex itself if necessary. */ -struct dentry *lookup_one_len_unlocked (const char *name, -struct dentry *base,int len) +struct dentry *lookup_one_unlocked (struct user_namespace *mnt_userns, +const char *name,struct dentry *base, +int len) {struct qstr this;int err;struct dentry *ret; - err =lookup_one_common (&init_user_ns, name, base, len, &this); + err =lookup_one_common (mnt_userns, name, base, len, &this);if (err)return ERR_PTR (err);
@@ -2745,6 +2747,59 @@ struct dentry *lookup_one_len_unlocked(c ret =lookup_slow (&this, base,0 );return ret; } +EXPORT_SYMBOL (lookup_one_unlocked); + +/** +* lookup_one_positive_unlocked - filesystem helper to lookup single +* pathname component +* @mnt_userns: idmapping of the mount the lookup is performed from +* @name: pathname component to lookup +* @base: base directory to lookup from +* @len: maximum length @len should be interpreted to +* +* This helper will yield ERR_PTR(-ENOENT) on negatives. The helper returns +* known positive or ERR_PTR(). This is what most of the users want. +* +* Note that pinned negative with unlocked parent _can_ become positive at any +* time, so callers of lookup_one_unlocked() need to be very careful; pinned +* positives have >d_inode stable, so this one avoids such problems. +* +* Note that this routine is purely a helper for filesystem usage and should +* not be called by generic code. +* +* The helper should be called without i_mutex held. +*/ +struct dentry *lookup_one_positive_unlocked (struct user_namespace *mnt_userns, +const char *name, +struct dentry *base,int len) +{ +struct dentry *ret =lookup_one_unlocked (mnt_userns, name, base, len); + +if (!IS_ERR (ret) &&d_flags_negative (smp_load_acquire (&ret->d_flags))) { +dput (ret); + ret =ERR_PTR (-ENOENT ); + } +return ret; +} +EXPORT_SYMBOL (lookup_one_positive_unlocked); + +/** +* lookup_one_len_unlocked - filesystem helper to lookup single pathname component +* @name: pathname component to lookup +* @base: base directory to lookup from +* @len: maximum length @len should be interpreted to +* +* Note that this routine is purely a helper for filesystem usage and should +* not be called by generic code. +* +* Unlike lookup_one_len, it should be called without the parent +* i_mutex held, and will take the i_mutex itself if necessary. +*/ +struct dentry *lookup_one_len_unlocked (const char *name, +struct dentry *base,int len) +{ +return lookup_one_unlocked (&init_user_ns, name, base, len); +}EXPORT_SYMBOL (lookup_one_len_unlocked);/*
@@ -2758,12 +2813,7 @@ EXPORT_SYMBOL(lookup_one_len_unlocked);struct dentry *lookup_positive_unlocked (const char *name,struct dentry *base,int len) { -struct dentry *ret =lookup_one_len_unlocked (name, base, len); -if (!IS_ERR (ret) &&d_flags_negative (smp_load_acquire (&ret->d_flags))) { -dput (ret); - ret =ERR_PTR (-ENOENT ); - } -return ret; +return lookup_one_positive_unlocked (&init_user_ns, name, base, len); }EXPORT_SYMBOL (lookup_positive_unlocked);
include/linux/namei.h +6 -0
@@ -69,6 +69,12 @@ extern struct dentry *lookup_one_len(conextern struct dentry *lookup_one_len_unlocked (const char *,struct dentry *,int );extern struct dentry *lookup_positive_unlocked (const char *,struct dentry *,int );struct dentry *lookup_one (struct user_namespace *,const char *,struct dentry *,int ); +struct dentry *lookup_one_unlocked (struct user_namespace *mnt_userns, +const char *name,struct dentry *base, +int len); +struct dentry *lookup_one_positive_unlocked (struct user_namespace *mnt_userns, +const char *name, +struct dentry *base,int len);extern int follow_down_one (struct path *);extern int follow_down (struct path *);
Greg Kroah-Hartman
maintainerPATCH 663/667 exportfs: support idmapped mounts
In reply to Greg Kroah-HartmanFrom: Christian Brauner <[email protected]>
commit 3a761d72fa62eec8913e45d29375344f61706541 upstream.
Make the two locations where exportfs helpers check permission to lookup a given inode idmapped mount aware by switching it to the lookup_one() helper. This is a bugfix for the open_by_handle_at() system call which doesn't take idmapped mounts into account currently. It's not tied to a specific commit so we'll just Cc stable.
In addition this is required to support idmapped base layers in overlay. The overlay filesystem uses exportfs to encode and decode file handles for its index=on mount option and when nfs_export=on.
--- fs/exportfs/expfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/exportfs/expfs.c +3 -2
@@ -145,7 +145,7 @@ static struct dentry *reconnect_one(struif (err) goto out_err;dprintk ("%s: found name: %s\n" , __func__, nbuf); - tmp =lookup_one_len_unlocked (nbuf, parent,strlen (nbuf)); + tmp =lookup_one_unlocked (mnt_user_ns (mnt), nbuf, parent,strlen (nbuf));if (IS_ERR (tmp)) {dprintk ("%s: lookup failed: %d\n" , __func__,PTR_ERR (tmp)); err =PTR_ERR (tmp);
@@ -525,7 +525,8 @@ exportfs_decode_fh_raw(struct vfsmount * }inode_lock (target_dir->d_inode); - nresult =lookup_one_len (nbuf, target_dir,strlen (nbuf)); + nresult =lookup_one (mnt_user_ns (mnt), nbuf, + target_dir,strlen (nbuf));if (!IS_ERR (nresult)) {if (unlikely (nresult->d_inode != result->d_inode)) {dput (nresult);
Greg Kroah-Hartman
maintainerPATCH 664/667 fs/ntfs3: Fix invalid free in log_replay
In reply to Greg Kroah-HartmanFrom: Namjae Jeon <[email protected]>
commit f26967b9f7a830e228bb13fb41bd516ddd9d789d upstream.
log_read_rst() returns ENOMEM error when there is not enough memory. In this case, if info is returned without initialization,
it attempts to kfree the uninitialized info->r_page pointer. This patch moves the memset initialization code to before log_read_rst() is called.
--- fs/ntfs3/fslog.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
fs/ntfs3/fslog.c +3 -3
@@ -1185,8 +1185,6 @@ static int log_read_rst(struct ntfs_logif (!r_page)return -ENOMEM ; -memset (info,0 ,sizeof (struct restart_info )); -/* Determine which restart area we are looking for. */ if (first) { vbo =0 ;
@@ -3791,10 +3789,11 @@ int log_replay(struct ntfs_inode *ni, boif (!log)return -ENOMEM ; +memset (&rst_info,0 ,sizeof (struct restart_info )); + log->ni = ni; log->l_size = l_size; log->one_page_buf =kmalloc (page_size,GFP_NOFS ); -if (!log->one_page_buf) { err = -ENOMEM ; goto out;
@@ -3842,6 +3841,7 @@ int log_replay(struct ntfs_inode *ni, boif (rst_info.vbo) goto check_restart_area; +memset (&rst_info2,0 ,sizeof (struct restart_info )); err =log_read_rst (log, l_size, false, &rst_info2);/* Determine which restart area to use. */
Greg Kroah-Hartman
maintainerPATCH 665/667 md: Dont set mddev private to NULL in raid0 pers->free
In reply to Greg Kroah-HartmanFrom: Xiao Ni <[email protected]>
commit 0f2571ad7a30ff6b33cde142439f9378669f8b4f upstream.
In normal stop process, it does like this:
do_md_stop
|
__md_stop (pers->free(); mddev->private=NULL)
| md_free (free mddev)__md_stop sets mddev->private to NULL after pers->free. The raid device will be stopped and mddev memory is free. But in reshape, it doesn't free the mddev and mddev will still be used in new raid.
In reshape, it first sets mddev->private to new_pers and then runs old_pers->free(). Now raid0 sets mddev->private to NULL in raid0_free. The new raid can't work anymore. It will panic when dereference mddev->private because of NULL pointer dereference.
It can panic like this:
[63010.814972] kernel BUG at drivers/md/raid10.c:928! [63010.819778] invalid opcode: 0000 [#1] PREEMPT SMP NOPTI [63010.825011] CPU: 3 PID: 44437 Comm: md0_resync Kdump: loaded Not tainted 5.14.0-86.el9.x86_64 #1 [63010.833789] Hardware name: Dell Inc. PowerEdge R6415/07YXFK, BIOS 1.15.0 09/11/2020 [63010.841440] RIP: 0010:raise_barrier+0x161/0x170 [raid10] [63010.865508] RSP: 0018:ffffc312408bbc10 EFLAGS: 00010246 [63010.870734] RAX: 0000000000000000 RBX: ffffa00bf7d39800 RCX: 0000000000000000 [63010.877866] RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffffa00bf7d39800 [63010.884999] RBP: 0000000000000000 R08: fffffa4945e74400 R09: 0000000000000000 [63010.892132] R10: ffffa00eed02f798 R11: 0000000000000000 R12: ffffa00bbc435200 [63010.899266] R13: ffffa00bf7d39800 R14: 0000000000000400 R15: 0000000000000003 [63010.906399] FS: 0000000000000000(0000) GS:ffffa00eed000000(0000) knlGS:0000000000000000 [63010.914485] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [63010.920229] CR2: 00007f5cfbe99828 CR3: 0000000105efe000 CR4: 00000000003506e0 [63010.927363] Call Trace: [63010.929822] ? bio_reset+0xe/0x40 [63010.933144] ? raid10_alloc_init_r10buf+0x60/0xa0 [raid10] [63010.938629] raid10_sync_request+0x756/0x1610 [raid10] [63010.943770] md_do_sync.cold+0x3e4/0x94c [63010.947698] md_thread+0xab/0x160 [63010.951024] ? md_write_inc+0x50/0x50 [63010.954688] kthread+0x149/0x170 [63010.957923] ? set_kthread_struct+0x40/0x40 [63010.962107] ret_from_fork+0x22/0x30
Removing the code that sets mddev->private to NULL in raid0 can fix problem.
--- drivers/md/raid0.c | 1 - 1 file changed, 1 deletion(-)
drivers/md/raid0.c +0 -1
@@ -361,7 +361,6 @@ static void free_conf(struct mddev *mddekfree (conf->strip_zone);kfree (conf->devlist);kfree (conf); - mddev->private =NULL ; }static void raid0_free (struct mddev *mddev,void *priv)
Greg Kroah-Hartman
maintainerPATCH 666/667 md: fix double free of io_acct_set bioset
In reply to Greg Kroah-HartmanFrom: Xiao Ni <[email protected]>
commit 42b805af102471f53e3c7867b8c2b502ea4eef7e upstream.
Now io_acct_set is alloc and free in personality. Remove the codes that free io_acct_set in md_free and md_stop.
--- drivers/md/md.c | 4 ---- 1 file changed, 4 deletions(-)
drivers/md/md.c +0 -4
@@ -5588,8 +5588,6 @@ static void md_free(struct kobject *ko)bioset_exit (&mddev->bio_set);bioset_exit (&mddev->sync_set); -if (mddev->level !=1 && mddev->level !=10 ) -bioset_exit (&mddev->io_acct_set);kfree (mddev); }
@@ -6277,8 +6275,6 @@ void md_stop(struct mddev *mddev)__md_stop (mddev);bioset_exit (&mddev->bio_set);bioset_exit (&mddev->sync_set); -if (mddev->level !=1 && mddev->level !=10 ) -bioset_exit (&mddev->io_acct_set); }EXPORT_SYMBOL_GPL (md_stop);
Greg Kroah-Hartman
maintainerPATCH 667/667 md: bcache: check the return value of kzalloc() in detached_dev_do_request()
In reply to Greg Kroah-HartmanFrom: Jia-Ju Bai <[email protected]>
commit 40f567bbb3b0639d2ec7d1c6ad4b1b018f80cf19 upstream.
The function kzalloc() in detached_dev_do_request() can fail, so its return value should be checked.
--- drivers/md/bcache/request.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/md/bcache/request.c +6 -0
@@ -1107,6 +1107,12 @@ static void detached_dev_do_request(stru* which would call closure_get(&dc->disk.cl) */ ddip =kzalloc (sizeof (struct detached_dev_io_private ),GFP_NOIO ); +if (!ddip) { + bio->bi_status =BLK_STS_RESOURCE ; + bio->bi_end_io (bio); +return ; + } + ddip->d = d;/* Count on the bcache device */ ddip->orig_bdev = orig_bdev;
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 5.15.46 release. There are 667 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Thu, 09 Jun 2022 16:48:02 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 9 lines
https://www.kernel.org/pub/linux/kernel/v5.x/stable-review/patch-5.15.46-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-5.15.y
and the diffstat can be found below.thanks,
greg k-h
5.15.46-rc1 Successfully Compiled and booted on my Raspberry PI 4b (8g) (bcm2711)
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 5.15.46 release. There are 667 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Thu, 09 Jun 2022 16:48:02 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 9 lines
https://www.kernel.org/pub/linux/kernel/v5.x/stable-review/patch-5.15.46-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-5.15.y
and the diffstat can be found below.thanks,
greg k-h
Compiled and booted on my test system. No dmesg regressions.
thanks,
-- Shuah
Hi Greg,
Quoted 7 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 5.15.46 release. There are 667 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Thu, 09 Jun 2022 16:48:02 +0000. Anything received after that time might be too late.
Build test (gcc version 11.3.1 20220606):
mips: 62 configs -> no failure
arm: 99 configs -> no failure
arm64: 3 configs -> no failurex86_64: 4 configs -> no failure
alpha allmodconfig -> no failure
csky allmodconfig -> no failure
riscv allmodconfig -> no failure
s390 allmodconfig -> no failure
xtensa allmodconfig -> no failure
Boot test:x86_64: Booted on my test laptop. No regression.x86_64: Booted on qemu. No regression. [1]
arm64: Booted on rpi4b (4GB model). No regression. [2]
mips: Booted on ci20 board. No regression. [3]
[1]. https://openqa.qa.codethink.co.uk/tests/1289
[2]. https://openqa.qa.codethink.co.uk/tests/1293
[3]. https://openqa.qa.codethink.co.uk/tests/1295
--
Regards
Sudip
Hi Greg,
Quoted 12 lines · Sudip Mukherjee
Hi Greg,
Quoted 7 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 5.15.46 release. There are 667 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Thu, 09 Jun 2022 16:48:02 +0000. Anything received after that time might be too late.
Quoted 10 lines
Build test (gcc version 11.3.1 20220606):
mips: 62 configs -> no failure
arm: 99 configs -> no failure
arm64: 3 configs -> no failurex86_64: 4 configs -> no failure alpha allmodconfig -> no failure csky allmodconfig -> no failure riscv allmodconfig -> no failure s390 allmodconfig -> no failure xtensa allmodconfig -> no failure
I did not mention powerpc allmodconfig failed to build as I have just started building that arch and I did not have a good build to know if its a new failure or not.
But It failed with the error:
{standard input}: Assembler messages:
{standard input}:255: Error: unrecognized opcode: `dssall'
make[2]: *** [scripts/Makefile.build:288: arch/powerpc/mm/mmu_context.o] Error 1
and will need - d51f86cfd8e3 ("powerpc/mm: Switch obsolete dssall to .long")
Signature · 2 lines
Regards Sudip
Quoted 27 lines · Sudip Mukherjee
Hi Greg,
Quoted 12 lines · Sudip Mukherjee
Hi Greg,
Quoted 7 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 5.15.46 release. There are 667 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Thu, 09 Jun 2022 16:48:02 +0000. Anything received after that time might be too late.
Quoted 10 lines
Build test (gcc version 11.3.1 20220606):
mips: 62 configs -> no failure
arm: 99 configs -> no failure
arm64: 3 configs -> no failurex86_64: 4 configs -> no failure alpha allmodconfig -> no failure csky allmodconfig -> no failure riscv allmodconfig -> no failure s390 allmodconfig -> no failure xtensa allmodconfig -> no failure
Quoted 4 lines
I did not mention powerpc allmodconfig failed to build as I have just started building that arch and I did not have a good build to know if its a new failure or not.
It is not new with gcc 11.3 and binutils 2.38. I currently use gcc 11.2.0 combined with binutils 2.36.1 for building powerpc images (binutils 2.37 won't work, at least not with gcc 11.2).
Guenter
Quoted 7 lines
But It failed with the error:
{standard input}: Assembler messages:
{standard input}:255: Error: unrecognized opcode: `dssall'
make[2]: *** [scripts/Makefile.build:288:arch/powerpc/mm/mmu_context.o] Error 1and will need -
d51f86cfd8e3("powerpc/mm: Switch obsolete dssall to .long")
With this patch applied, at least the affected file builds with gcc 11.3 / binutils 2.38. I have not tried to build the entire image, though, with that combination.
Guenter
Quoted 5 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 5.15.46 release. There are 667 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Successfully cross-compiled for arm (multi_v7_defconfig, GCC 12.1.0) and arm64 (bcm2711_defconfig, GCC 12.1.0).
Signature · 1 line
An old man doll... just what I always wanted! - Clara
Quoted 10 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 5.15.46 release. There are 667 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Thu, 09 Jun 2022 16:48:02 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v5.x/stable-review/patch-5.15.46-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-5.15.y
and the diffstat can be found below.thanks,
greg k-h
Results from Linaro’s test farm.
No regressions on arm64, arm, x86_64, and i386.
## Build
* kernel: 5.15.46-rc1
* git: https://gitlab.com/Linaro/lkft/mirrors/stable/linux-stable-rc
* git branch: linux-5.15.y
* git commit: 53f46ca17ebdfbda0ddab0ba7aaad7c9b2493f02
* git describe: v5.15.45-668-g53f46ca17ebd
* test details:
https://qa-reports.linaro.org/lkft/linux-stable-rc-linux-5.15.y/build/v5.15.45-668-g53f46ca17ebd
## Test Regressions (compared to v5.15.43-213-g207ca688162d) No test regressions found.
## Metric Regressions (compared to v5.15.43-213-g207ca688162d) No metric regressions found.
## Test Fixes (compared to v5.15.43-213-g207ca688162d) No test fixes found.
## Metric Fixes (compared to v5.15.43-213-g207ca688162d) No metric fixes found.
## Test result summary
total: 135584, pass: 122903, fail: 248, skip: 11845, xfail: 588
## Build Summary
* arm: 17 total, 14 passed, 3 failed
* arm64: 20 total, 20 passed, 0 failed
* i386: 17 total, 12 passed, 5 failed
* mips: 4 total, 1 passed, 3 failed
* parisc: 2 total, 2 passed, 0 failed
* powerpc: 5 total, 2 passed, 3 failed
* riscv: 5 total, 5 passed, 0 failed
* s390: 5 total, 2 passed, 3 failed
* sh: 2 total, 0 passed, 2 failed
* sparc: 2 total, 2 passed, 0 failed
* x86_64: 20 total, 20 passed, 0 failed
## Test suites summary
* fwts
* kunit
* kvm-unit-tests
* libgpiod
* libhugetlbfs
* log-parser-boot
* log-parser-test
* ltp-cap_bounds
* ltp-cap_bounds-tests
* ltp-commands
* ltp-commands-tests
* ltp-containers
* ltp-containers-tests
* ltp-controllers-tests
* ltp-cpuhotplug-tests
* ltp-crypto
* ltp-crypto-tests
* ltp-cve-tests
* ltp-dio-tests
* ltp-fcntl-locktests
* ltp-fcntl-locktests-tests
* ltp-filecaps
* ltp-filecaps-tests
* ltp-fs
* ltp-fs-tests
* ltp-fs_bind
* ltp-fs_bind-tests
* ltp-fs_perms_simple
* ltp-fs_perms_simple-tests
* ltp-fsx
* ltp-fsx-tests
* ltp-hugetlb
* ltp-hugetlb-tests
* ltp-io
* ltp-io-tests
* ltp-ipc
* ltp-ipc-tests
* ltp-math-tests
* ltp-mm-tests
* ltp-nptl
* ltp-nptl-tests
* ltp-open-posix-tests
* ltp-pty
* ltp-pty-tests
* ltp-sched-tests
* ltp-securebits
* ltp-securebits-tests
* ltp-syscalls-tests
* ltp-tracing-tests
* network-basic-tests
* packetdrill
* perf
* perf/Zstd-perf.data-compression
* rcutorture
* ssuite
* v4l2-compliance
* vdso
--
Linaro LKFT
https://lkft.linaro.org
Quoted 8 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 5.15.46 release. There are 667 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Thu, 09 Jun 2022 16:48:02 +0000. Anything received after that time might be too late.
Build results:
total: 159 pass: 159 fail: 0 Qemu test results: total: 488 pass: 488 fail: 0
Guenter
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 5.15.46 release. There are 667 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Thu, 09 Jun 2022 16:48:02 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v5.x/stable-review/patch-5.15.46-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-5.15.y
and the diffstat can be found below.thanks,
greg k-h
Built and booted successfully on RISC-V RV64 (HiFive Unmatched).