diff --git a/kernel_patches_daemon/branch_worker.py b/kernel_patches_daemon/branch_worker.py index 7574911..df6363b 100644 --- a/kernel_patches_daemon/branch_worker.py +++ b/kernel_patches_daemon/branch_worker.py @@ -37,7 +37,11 @@ from github.Repository import Repository from github.WorkflowJob import WorkflowJob -from kernel_patches_daemon.config import EmailConfig +from kernel_patches_daemon.config import ( + SERIES_ID_SEPARATOR, + SERIES_TARGET_SEPARATOR, + EmailConfig, +) from kernel_patches_daemon.github_connector import GithubConnector from kernel_patches_daemon.github_logs import GithubFailedJobLog, GithubLogExtractor from kernel_patches_daemon.patchwork import Patchwork, Series, Subject @@ -79,7 +83,7 @@ ALREADY_MERGED_LOOKBACK = 100 BRANCH_TTL = 172800 # 1 week PULL_REQUEST_TTL = timedelta(days=7) -HEAD_BASE_SEPARATOR = "=>" + KNOWN_OK_COMMENT_EXCEPTIONS = { "Commenting is disabled on issues with more than 2500 comments" } @@ -398,21 +402,36 @@ def create_color_labels(labels_cfg: Dict[str, str], repo: Repository) -> None: repo.create_label(name=label, color=color) -def get_base_branch_from_ref(ref: str) -> str: - return ref.split(HEAD_BASE_SEPARATOR)[0] +def parse_pr_ref(ref: str) -> Dict[str, Any]: + # "series/123456=>target-branch" -> + # { + # "series": "series/123456", + # "series_id": 123456, + # "target": "target-branch", + # } + res = {} + tmp = ref.split(SERIES_TARGET_SEPARATOR, maxsplit=1) + res["series"] = tmp[0] + if len(tmp) >= 2: + res["target"] = tmp[1] + tmp = res["series"].split("/", maxsplit=1) + if len(tmp) >= 2: + res["series_id"] = int(tmp[1]) -def has_same_base_different_remote(ref: str, other_ref: str) -> bool: - if ref == other_ref: - return False + return res - base = get_base_branch_from_ref(ref) - other_base = get_base_branch_from_ref(other_ref) - if base != other_base: - return False +def parsed_pr_ref_ok(parsed_ref: Dict[str, Any]) -> bool: + return "target" in parsed_ref and "series_id" in parsed_ref - return True + +def same_series_different_target(ref: str, other_ref: str) -> bool: + if ref == other_ref: + return False + ref1 = parse_pr_ref(ref) + ref2 = parse_pr_ref(other_ref) + return ref1["series"] == ref2["series"] and ref1["target"] != ref2["target"] def _reset_repo(repo, branch: str) -> None: @@ -1081,7 +1100,8 @@ def filter_closed_pr(self, head: str) -> Optional[PullRequest]: return res async def subject_to_branch(self, subject: Subject) -> str: - return f"{await subject.branch}{HEAD_BASE_SEPARATOR}{self.repo_branch}" + subj_branch = await subject.branch() + return f"{subj_branch}{SERIES_TARGET_SEPARATOR}{self.repo_branch}" async def sync_checks(self, pr: PullRequest, series: Series) -> None: # Make sure that we are working with up-to-date data (as opposed to @@ -1224,9 +1244,10 @@ def expire_branches(self) -> None: # that are not belong to any known open prs continue - if HEAD_BASE_SEPARATOR in branch: - split = branch.split(HEAD_BASE_SEPARATOR) - if len(split) > 1 and split[1] == self.repo_branch: + parsed_ref = parse_pr_ref(branch) + + if parsed_pr_ref_ok(parsed_ref): + if parsed_ref["target"] == self.repo_branch: # which have our repo_branch as target # that doesn't have any closed PRs # with last update within defined TTL diff --git a/kernel_patches_daemon/config.py b/kernel_patches_daemon/config.py index 294c450..b1f6bd6 100644 --- a/kernel_patches_daemon/config.py +++ b/kernel_patches_daemon/config.py @@ -17,6 +17,9 @@ logger = logging.getLogger(__name__) +SERIES_TARGET_SEPARATOR = "=>" +SERIES_ID_SEPARATOR = "/" + class UnsupportedConfigVersion(ValueError): def __init__(self, version: int) -> None: diff --git a/kernel_patches_daemon/github_sync.py b/kernel_patches_daemon/github_sync.py index 7be23ee..890ae5f 100644 --- a/kernel_patches_daemon/github_sync.py +++ b/kernel_patches_daemon/github_sync.py @@ -15,12 +15,16 @@ from github.PullRequest import PullRequest from kernel_patches_daemon.branch_worker import ( BranchWorker, - get_base_branch_from_ref, - has_same_base_different_remote, - HEAD_BASE_SEPARATOR, + parsed_pr_ref_ok, + same_series_different_target, + parse_pr_ref, NewPRWithNoChangeException, ) -from kernel_patches_daemon.config import BranchConfig, KPDConfig +from kernel_patches_daemon.config import ( + SERIES_TARGET_SEPARATOR, + BranchConfig, + KPDConfig, +) from kernel_patches_daemon.github_logs import ( BpfGithubLogExtractor, DefaultGithubLogExtractor, @@ -133,7 +137,8 @@ def __init__( async def get_mapped_branches(self, series: Series) -> List[str]: for tag in self.tag_to_branch_mapping: - if tag in await series.all_tags(): + series_tags = await series.all_tags() + if tag in series_tags: mapped_branches = self.tag_to_branch_mapping[tag] logging.info(f"Tag '{tag}' mapped to branch order {mapped_branches}") return mapped_branches @@ -142,20 +147,20 @@ async def get_mapped_branches(self, series: Series) -> List[str]: logging.info(f"Mapped to default branch order: {mapped_branches}") return mapped_branches - def close_existing_prs_with_same_base( + def close_existing_prs_for_series( self, workers: Sequence["BranchWorker"], pr: PullRequest ) -> None: - """Close existing pull requests with the same base, but different remote branch + """Close existing pull requests for the same series, but different target branch For given pull request, find all other pull requests with - the same base, but different remote branch and close them. + the same series name, but different remote branch and close them. """ prs_to_close = [ existing_pr for worker in workers for existing_pr in worker.prs.values() - if has_same_base_different_remote(pr.head.ref, existing_pr.head.ref) + if same_series_different_target(pr.head.ref, existing_pr.head.ref) ] # Remove matching PRs from other workers for pr_to_close in prs_to_close: @@ -169,7 +174,7 @@ def close_existing_prs_with_same_base( del worker.prs[pr_to_close.title] async def checkout_and_patch_safe( - self, worker, branch_name: str, series_to_apply: Series + self, worker: BranchWorker, branch_name: str, series_to_apply: Series ) -> Optional[PullRequest]: try: self.increment_counter("all_known_subjects") @@ -186,6 +191,56 @@ async def checkout_and_patch_safe( ) return None + async def sync_relevant_subject(self, subject: Subject) -> None: + """ + 1. Get Subject's latest series + 2. Get series tags + 3. Map tags to a branches + 4. Start from first branch, try to apply and generate PR, + if fails continue to next branch, if no more branches, generate a merge-conflict PR + """ + series = none_throws(await subject.latest_series()) + tags = await series.all_tags() + logging.info(f"Processing {series.id}: {subject.subject} (tags: {tags})") + + mapped_branches = await self.get_mapped_branches(series) + if len(mapped_branches) == 0: + logging.info( + f"Skipping {series.id}: {subject.subject} for no mapped branches." + ) + return + + last_branch = mapped_branches[-1] + for branch in mapped_branches: + worker = self.workers[branch] + # PR branch name == sid of the first known series + pr_branch_name = await worker.subject_to_branch(subject) + (applied, _, _) = await worker.try_apply_mailbox_series( + pr_branch_name, series + ) + if not applied: + msg = f"Failed to apply series to {branch}, " + if branch != last_branch: + logging.info(msg + "moving to next.") + continue + else: + logging.info(msg + "no more next, staying.") + + logging.info(f"Choosing branch {branch} to create/update PR.") + pr = await self.checkout_and_patch_safe(worker, pr_branch_name, series) + if pr is None: + continue + + logging.info( + f"Created/updated {pr} ({pr.head.ref}): {pr.url} for series {series.id}" + ) + await worker.sync_checks(pr, series) + # Close out other PRs if exists + self.close_existing_prs_for_series(list(self.workers.values()), pr) + + break + pass + async def sync_patches(self) -> None: """ One subject = one branch @@ -208,7 +263,8 @@ async def sync_patches(self) -> None: await loop.run_in_executor(None, worker.get_pulls) await loop.run_in_executor(None, worker.do_sync) worker._closed_prs = None - worker.branches = [x.name for x in worker.repo.get_branches()] + branches = worker.repo.get_branches() + worker.branches = [b.name for b in branches] mirror_done = time.time() @@ -223,52 +279,8 @@ async def sync_patches(self) -> None: pw_done = time.time() - # 1. Get Subject's latest series - # 2. Get series tags - # 3. Map tags to a branches - # 4. Start from first branch, try to apply and generate PR, - # if fails continue to next branch, if no more branches, generate a merge-conflict PR for subject in self.subjects: - series = none_throws(await subject.latest_series) - logging.info( - f"Processing {series.id}: {subject.subject} (tags: {await series.all_tags()})" - ) - - mapped_branches = await self.get_mapped_branches(series) - # series to apply - last known series - if len(mapped_branches) == 0: - logging.info( - f"Skipping {series.id}: {subject.subject} for no mapped branches." - ) - continue - last_branch = mapped_branches[-1] - for branch in mapped_branches: - worker = self.workers[branch] - # PR branch name == sid of the first known series - pr_branch_name = await worker.subject_to_branch(subject) - apply_mbox = await worker.try_apply_mailbox_series( - pr_branch_name, series - ) - if not apply_mbox[0]: - msg = f"Failed to apply series to {branch}, " - if branch != last_branch: - logging.info(msg + "moving to next.") - continue - else: - logging.info(msg + "no more next, staying.") - logging.info(f"Choosing branch {branch} to create/update PR.") - pr = await self.checkout_and_patch_safe(worker, pr_branch_name, series) - if pr is None: - continue - - logging.info( - f"Created/updated {pr} ({pr.head.ref}): {pr.url} for series {series.id}" - ) - await worker.sync_checks(pr, series) - # Close out other PRs if exists - self.close_existing_prs_with_same_base(list(self.workers.values()), pr) - - break + await self.sync_relevant_subject(subject) # sync old subjects subject_names = {x.subject for x in self.subjects} @@ -278,11 +290,12 @@ async def sync_patches(self) -> None: continue if worker._is_relevant_pr(pr): + parsed_ref = parse_pr_ref(pr.head.ref) # ignore unknown format branch/PRs. - if "/" not in pr.head.ref or HEAD_BASE_SEPARATOR not in pr.head.ref: + if parsed_pr_ref_ok(parsed_ref): continue - series_id = int(get_base_branch_from_ref(pr.head.ref.split("/")[1])) + series_id = parsed_ref["series_id"] series = await self.pw.get_series_by_id(series_id) subject = self.pw.get_subject_by_series(series) if subject_name != subject.subject: @@ -290,8 +303,8 @@ async def sync_patches(self) -> None: f"Renaming {pr} from {subject_name} to {subject.subject} according to {series.id}" ) pr.edit(title=subject.subject) - branch_name = f"{await subject.branch}{HEAD_BASE_SEPARATOR}{worker.repo_branch}" - latest_series = await subject.latest_series or series + branch_name = await worker.subject_to_branch(subject) + latest_series = await subject.latest_series() or series pr = await self.checkout_and_patch_safe( worker, branch_name, latest_series ) diff --git a/kernel_patches_daemon/patchwork.py b/kernel_patches_daemon/patchwork.py index c2fd4e1..d49c05d 100644 --- a/kernel_patches_daemon/patchwork.py +++ b/kernel_patches_daemon/patchwork.py @@ -23,6 +23,7 @@ from aiohttp_retry import ExponentialRetry, RetryClient from cachetools import TTLCache +from kernel_patches_daemon.config import SERIES_ID_SEPARATOR from kernel_patches_daemon.status import Status from multidict import MultiDict @@ -288,21 +289,18 @@ def __init__(self, subject: str, pw_client: "Patchwork") -> None: self.pw_client = pw_client self.subject = subject - @property async def branch(self) -> Optional[str]: - relevant_series = await self.relevant_series + relevant_series = await self.relevant_series() if len(relevant_series) == 0: return None - return f"series/{relevant_series[0].id}" + return f"series{SERIES_ID_SEPARATOR}{relevant_series[0].id}" - @property async def latest_series(self) -> Optional["Series"]: - relevant_series = await self.relevant_series + relevant_series = await self.relevant_series() if len(relevant_series) == 0: return None return relevant_series[-1] - @property @cached(cache=TTLCache(maxsize=1, ttl=600)) async def relevant_series(self) -> List["Series"]: """ @@ -580,7 +578,8 @@ async def __get_objects_recursive( params = {} while True: response = await self.__get(path, params=params) - items += await response.json() + j = await response.json() + items += j if "next" not in response.links: break @@ -695,9 +694,8 @@ async def post_check_for_patch_id( async def get_series_by_id(self, series_id: int) -> Series: # fetches directly only if series is not available in local scope if series_id not in self.known_series: - self.known_series[series_id] = Series( - self, await self.__get_object_by_id("series", series_id) - ) + series_json = await self.__get_object_by_id("series", series_id) + self.known_series[series_id] = Series(self, series_json) return self.known_series[series_id] @@ -767,7 +765,7 @@ async def get_relevant_subjects(self) -> Sequence[Subject]: async def fetch_latest_series( subject_name, subject_obj ) -> Tuple[str, Series, Optional[Series]]: - return (subject_name, subject_obj, await subject_obj.latest_series) + return (subject_name, subject_obj, await subject_obj.latest_series()) tasks = [fetch_latest_series(k, v) for k, v in subjects.items()] tasks = await asyncio.gather(*tasks) diff --git a/tests/common/patchwork_mock.py b/tests/common/patchwork_mock.py index 072720a..578b67a 100644 --- a/tests/common/patchwork_mock.py +++ b/tests/common/patchwork_mock.py @@ -6,8 +6,11 @@ # pyre-unsafe +import json +import os import re -from typing import Any, Dict, Final + +from typing import Any, Dict, Final, List from aioresponses import aioresponses @@ -78,6 +81,33 @@ def get_dict_key(d: Dict[str, Any], idx: int = 0) -> str: return list(d)[idx] +def load_test_data_file(file): + with open(file, "r") as f: + if file.endswith(".json"): + return json.load(f) + else: + return f.read() + + +def load_test_data(path) -> Dict[str, Any]: + jsons_by_path = {} + with open(os.path.join(path, "responses.json"), "r") as f: + jsons_by_path = json.load(f) + data = {} + for url, value in jsons_by_path.items(): + match value: + case str(): + filepath = os.path.join(path, value) + data[url] = load_test_data_file(filepath) + case list(): + lst = [] + for filename in value: + filepath = os.path.join(path, filename) + lst.append(load_test_data_file(filepath)) + data[url] = lst + return data + + FOO_SERIES_FIRST = 2 FOO_SERIES_LAST = 10 diff --git a/tests/data/test_github_sync.test_sync_patches_pr_summary_success/patch-14114605.json b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/patch-14114605.json new file mode 100644 index 0000000..46bcc4b --- /dev/null +++ b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/patch-14114605.json @@ -0,0 +1,88 @@ +{ + "id": 14114605, + "url": "https://patchwork.test/api/1.1/patches/14114605/", + "web_url": "https://patchwork.test/project/netdevbpf/patch/20250611154859.259682-1-chen.dylane@linux.dev/", + "project": { + "id": 399, + "url": "https://patchwork.test/api/1.1/projects/399/", + "name": "Netdev + BPF", + "link_name": "netdevbpf", + "list_id": "bpf.vger.kernel.org", + "list_email": "bpf@vger.kernel.org", + "web_url": "", + "scm_url": "", + "webscm_url": "" + }, + "msgid": "<20250611154859.259682-1-chen.dylane@linux.dev>", + "date": "2025-06-11T15:48:58", + "name": "[bpf-next] bpf: clear user buf when bpf_d_path failed", + "commit_ref": "3b55a9e6738b7b82a7c57ebaa484aabd0c9d36bd", + "pull_url": null, + "state": "new", + "archived": false, + "hash": "ecb10e6ecea01d3f770e4d08eb251179b0f9a98b", + "submitter": { + "id": 216065, + "url": "https://patchwork.test/api/1.1/people/216065/", + "name": "Tao Chen", + "email": "chen.dylane@linux.dev" + }, + "delegate": { + "id": 121173, + "url": "https://patchwork.test/api/1.1/users/121173/", + "username": "bpf", + "first_name": "BPF", + "last_name": "", + "email": "bpf@iogearbox.net" + }, + "mbox": "https://patchwork.test/project/netdevbpf/patch/20250611154859.259682-1-chen.dylane@linux.dev/mbox/", + "series": [ + { + "id": 970926, + "url": "https://patchwork.test/api/1.1/series/970926/", + "web_url": "https://patchwork.test/project/netdevbpf/list/?series=970926", + "date": "2025-06-11T15:48:58", + "name": "[bpf-next] bpf: clear user buf when bpf_d_path failed", + "version": 1, + "mbox": "https://patchwork.test/series/970926/mbox/" + } + ], + "comments": "https://patchwork.test/api/patches/14114605/comments/", + "check": "success", + "checks": "https://patchwork.test/api/patches/14114605/checks/", + "tags": {}, + "headers": { + "Received": "from out-186.mta0.migadu.com (out-186.mta0.migadu.com\n [91.218.175.186])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 29219198E75\n\tfor ; Wed, 11 Jun 2025 15:49:31 +0000 (UTC)", + "Authentication-Results": [ + "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=91.218.175.186", + "smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=linux.dev", + "smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=linux.dev", + "smtp.subspace.kernel.org;\n\tdkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev\n header.b=\"BLMetV01\"" + ], + "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1749656974; cv=none;\n b=H3sJmO/4HOlIx6kUFl6H/+BRA9KPHHH4Q7GjlSA/LngQ6EFecK1QUciBapIR6C34s0H1sz1+glg3v1exuzPTkszlKJv44cGH+VioXoRre8Y0iWC1KVwdc7RHvgffJ0XPGihrNjrcuJjt4YmUCnouwVszIm4By1xzu3Sb6+nLec8=", + "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1749656974; c=relaxed/simple;\n\tbh=Vsu5Xaf2CfmWYXrEWUU8kTg6xy3/CnahfubB8AomyEw=;\n\th=From:To:Cc:Subject:Date:Message-ID:MIME-Version;\n b=dncJRD9nOpjZrsdcvYkxd2CfccDyNQ8uHadiFb/G4K5K4GAr1MRjBv/suIeI85s0iKBmv5NZ3r2PFI1g9Yus7+jBZ5z/wo42zqDVLhXSK87Dx3X+clSbiW9VqQ7wzQM1/2xFRgNIlZ12hswHopIjCQCr+w52ofYIXiH5Ug7o85Q=", + "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=linux.dev;\n spf=pass smtp.mailfrom=linux.dev;\n dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev\n header.b=BLMetV01; arc=none smtp.client-ip=91.218.175.186", + "X-Report-Abuse": "Please report any abuse attempt to abuse@migadu.com and\n include these headers.", + "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1;\n\tt=1749656960;\n\th=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n\t to:to:cc:cc:mime-version:mime-version:\n\t content-transfer-encoding:content-transfer-encoding;\n\tbh=NkpbyMsiJRwWnx6iOR+RLlbhyzNlbJ3e38I3A+4NmfI=;\n\tb=BLMetV01lS4FXWjpoxALr+a7Mi0irlvKqYcAZBywjBIwgNGKzGMwf6SP0SwobrqhyTbR8H\n\tNQ/nTgeRdr9+LbZ4t/A+vxRUTO28kF4R6uvFYTrAwmTj5i/qgFhOAX9bHiICSohUcwmfK3\n\tWvRPHYKGvp0Puq6S/5gBm2Q5AFHG7m4=", + "From": "Tao Chen ", + "To": "kpsingh@kernel.org,\n\tmattbobrowski@google.com,\n\tast@kernel.org,\n\tdaniel@iogearbox.net,\n\tandrii@kernel.org,\n\tmartin.lau@linux.dev,\n\teddyz87@gmail.com,\n\tsong@kernel.org,\n\tyonghong.song@linux.dev,\n\tjohn.fastabend@gmail.com,\n\tsdf@fomichev.me,\n\thaoluo@google.com,\n\tjolsa@kernel.org,\n\trostedt@goodmis.org,\n\tmhiramat@kernel.org,\n\tmathieu.desnoyers@efficios.com", + "Cc": "bpf@vger.kernel.org,\n\tlinux-kernel@vger.kernel.org,\n\tlinux-trace-kernel@vger.kernel.org,\n\tTao Chen ", + "Subject": "[PATCH bpf-next] bpf: clear user buf when bpf_d_path failed", + "Date": "Wed, 11 Jun 2025 23:48:58 +0800", + "Message-ID": "<20250611154859.259682-1-chen.dylane@linux.dev>", + "Precedence": "bulk", + "X-Mailing-List": "bpf@vger.kernel.org", + "List-Id": "", + "List-Subscribe": "", + "List-Unsubscribe": "", + "MIME-Version": "1.0", + "Content-Transfer-Encoding": "8bit", + "X-Migadu-Flow": "FLOW_OUT", + "X-Patchwork-Delegate": "bpf@iogearbox.net" + }, + "content": "The bpf_d_path() function may fail. If it does,\nclear the user buf, like bpf_probe_read etc.\n\nSigned-off-by: Tao Chen \n---\n kernel/trace/bpf_trace.c | 5 ++++-\n 1 file changed, 4 insertions(+), 1 deletion(-)", + "diff": "diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c\nindex 0998cbbb963..bb1003cb271 100644\n--- a/kernel/trace/bpf_trace.c\n+++ b/kernel/trace/bpf_trace.c\n@@ -916,11 +916,14 @@ BPF_CALL_3(bpf_d_path, struct path *, path, char *, buf, u32, sz)\n \t * potentially broken verifier.\n \t */\n \tlen = copy_from_kernel_nofault(©, path, sizeof(*path));\n-\tif (len < 0)\n+\tif (len < 0) {\n+\t\tmemset(buf, 0, sz);\n \t\treturn len;\n+\t}\n \n \tp = d_path(©, buf, sz);\n \tif (IS_ERR(p)) {\n+\t\tmemset(buf, 0, sz);\n \t\tlen = PTR_ERR(p);\n \t} else {\n \t\tlen = buf + sz - p;\n", + "prefixes": [ + "bpf-next" + ] +} diff --git a/tests/data/test_github_sync.test_sync_patches_pr_summary_success/patch-14114773.json b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/patch-14114773.json new file mode 100644 index 0000000..e6542f8 --- /dev/null +++ b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/patch-14114773.json @@ -0,0 +1,92 @@ +{ + "id": 14114773, + "url": "https://patchwork.test/api/1.1/patches/14114773/", + "web_url": "https://patchwork.test/project/netdevbpf/patch/20250611171524.2033657-1-yonghong.song@linux.dev/", + "project": { + "id": 399, + "url": "https://patchwork.test/api/1.1/projects/399/", + "name": "Netdev + BPF", + "link_name": "netdevbpf", + "list_id": "bpf.vger.kernel.org", + "list_email": "bpf@vger.kernel.org", + "web_url": "", + "scm_url": "", + "webscm_url": "" + }, + "msgid": "<20250611171524.2033657-1-yonghong.song@linux.dev>", + "date": "2025-06-11T17:15:24", + "name": "[bpf-next,v2,1/3] bpf: Fix an issue in bpf_prog_test_run_xdp when page size greater than 4K", + "commit_ref": null, + "pull_url": null, + "state": "changes-requested", + "archived": false, + "hash": "3d9e0c54fee868ec1c6ac264e57d215139d12f22", + "submitter": { + "id": 210263, + "url": "https://patchwork.test/api/1.1/people/210263/", + "name": "Yonghong Song", + "email": "yonghong.song@linux.dev" + }, + "delegate": { + "id": 121173, + "url": "https://patchwork.test/api/1.1/users/121173/", + "username": "bpf", + "first_name": "BPF", + "last_name": "", + "email": "bpf@iogearbox.net" + }, + "mbox": "https://patchwork.test/project/netdevbpf/patch/20250611171524.2033657-1-yonghong.song@linux.dev/mbox/", + "series": [ + { + "id": 970968, + "url": "https://patchwork.test/api/1.1/series/970968/", + "web_url": "https://patchwork.test/project/netdevbpf/list/?series=970968", + "date": "2025-06-11T17:15:19", + "name": "bpf: Fix a few test failures with 64K page size", + "version": 2, + "mbox": "https://patchwork.test/series/970968/mbox/" + } + ], + "comments": "https://patchwork.test/api/patches/14114773/comments/", + "check": "warning", + "checks": "https://patchwork.test/api/patches/14114773/checks/", + "tags": {}, + "headers": { + "Received": [ + "from 66-220-144-178.mail-mxout.facebook.com\n (66-220-144-178.mail-mxout.facebook.com [66.220.144.178])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id C2F7D176FB0\n\tfor ; Wed, 11 Jun 2025 17:15:36 +0000 (UTC)", + "by devvm16039.vll0.facebook.com (Postfix, from userid 128203)\n\tid C89EC9680C3C; Wed, 11 Jun 2025 10:15:24 -0700 (PDT)" + ], + "Authentication-Results": [ + "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=66.220.144.178", + "smtp.subspace.kernel.org;\n dmarc=fail (p=none dis=none) header.from=linux.dev", + "smtp.subspace.kernel.org;\n spf=fail smtp.mailfrom=linux.dev" + ], + "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1749662139; cv=none;\n b=MWtGjiv5fK+cfyuRZs91UdoeCkok6sC9xRNWjzHP/4OuyfIi7nYt9Uh9ABf7wvrPKCM+umpE8wW6C60TCiDu/tL2LQ+7CHkUu/UkgWIYHMbgQnPsdkAKexzFzaSt2eIpmLBx9Lxcjo91TG/QqgulAIBmdRvGGClMqQHN+LNN3PU=", + "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1749662139; c=relaxed/simple;\n\tbh=tsR3mgpai7tGsrvkBO1E4u9z0EoTaC8wsDyWMpIm5wA=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=TxC1UmhxgG3EnDDN74/3y6l5LD5NtwQf/Y8Wi7dhKf1aZ5sfeS+7I+xehvuoeaGIfcMqEIY2sj9k+4isAjND4bqCZohdKcd/69RPXFTkbL9LcgS6Xneh1fDwfGGcvTkuWmkczGmzlWNpu7p8FtkI5xrwa0WgWCoUbGtGqiqbhP4=", + "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dmarc=fail (p=none dis=none) header.from=linux.dev;\n spf=fail smtp.mailfrom=linux.dev; arc=none smtp.client-ip=66.220.144.178", + "From": "Yonghong Song ", + "To": "bpf@vger.kernel.org", + "Cc": "Alexei Starovoitov ,\n\tAndrii Nakryiko ,\n\tDaniel Borkmann ,\n\tkernel-team@fb.com,\n\tMartin KaFai Lau ", + "Subject": "[PATCH bpf-next v2 1/3] bpf: Fix an issue in bpf_prog_test_run_xdp\n when page size greater than 4K", + "Date": "Wed, 11 Jun 2025 10:15:24 -0700", + "Message-ID": "<20250611171524.2033657-1-yonghong.song@linux.dev>", + "X-Mailer": "git-send-email 2.47.1", + "In-Reply-To": "<20250611171519.2033193-1-yonghong.song@linux.dev>", + "References": "<20250611171519.2033193-1-yonghong.song@linux.dev>", + "Precedence": "bulk", + "X-Mailing-List": "bpf@vger.kernel.org", + "List-Id": "", + "List-Subscribe": "", + "List-Unsubscribe": "", + "MIME-Version": "1.0", + "Content-Transfer-Encoding": "quoted-printable", + "X-Patchwork-Delegate": "bpf@iogearbox.net" + }, + "content": "The bpf selftest xdp_adjust_tail/xdp_adjust_frags_tail_grow failed on\narm64 with 64KB page:\n xdp_adjust_tail/xdp_adjust_frags_tail_grow:FAIL\n\nIn bpf_prog_test_run_xdp(), the xdp->frame_sz is set to 4K, but later on\nwhen constructing frags, with 64K page size, the frag data_len could\nbe more than 4K. This will cause problems in bpf_xdp_frags_increase_tail().\n\nTo fix the failure, the xdp->frame_sz is set to be PAGE_SIZE so kernel\ncan test different page size properly. With the kernel change, the user\nspace and bpf prog needs adjustment. Currently, the MAX_SKB_FRAGS default\nvalue is 17, so for 4K page, the maximum packet size will be less than 68K.\nTo test 64K page, a bigger maximum packet size than 68K is desired. So two\ndifferent functions are implemented for subtest xdp_adjust_frags_tail_grow.\nDepending on different page size, different data input/output sizes are used\nto adapt with different page size.\n\nSigned-off-by: Yonghong Song \n---\n net/bpf/test_run.c | 2 +-\n .../bpf/prog_tests/xdp_adjust_tail.c | 95 +++++++++++++++++--\n .../bpf/progs/test_xdp_adjust_tail_grow.c | 8 +-\n 3 files changed, 96 insertions(+), 9 deletions(-)", + "diff": "diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c\nindex aaf13a7d58ed..9728dbd4c66c 100644\n--- a/net/bpf/test_run.c\n+++ b/net/bpf/test_run.c\n@@ -1255,7 +1255,7 @@ int bpf_prog_test_run_xdp(struct bpf_prog *prog, const union bpf_attr *kattr,\n \t\theadroom -= ctx->data;\n \t}\n \n-\tmax_data_sz = 4096 - headroom - tailroom;\n+\tmax_data_sz = PAGE_SIZE - headroom - tailroom;\n \tif (size > max_data_sz) {\n \t\t/* disallow live data mode for jumbo frames */\n \t\tif (do_live)\ndiff --git a/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c b/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c\nindex e361129402a1..133bde28a489 100644\n--- a/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c\n+++ b/tools/testing/selftests/bpf/prog_tests/xdp_adjust_tail.c\n@@ -37,21 +37,25 @@ static void test_xdp_adjust_tail_shrink(void)\n \tbpf_object__close(obj);\n }\n \n-static void test_xdp_adjust_tail_grow(void)\n+static void test_xdp_adjust_tail_grow(bool is_64k_pagesize)\n {\n \tconst char *file = \"./test_xdp_adjust_tail_grow.bpf.o\";\n \tstruct bpf_object *obj;\n-\tchar buf[4096]; /* avoid segfault: large buf to hold grow results */\n+\tchar buf[8192]; /* avoid segfault: large buf to hold grow results */\n \t__u32 expect_sz;\n \tint err, prog_fd;\n \tLIBBPF_OPTS(bpf_test_run_opts, topts,\n \t\t.data_in = &pkt_v4,\n-\t\t.data_size_in = sizeof(pkt_v4),\n \t\t.data_out = buf,\n \t\t.data_size_out = sizeof(buf),\n \t\t.repeat = 1,\n \t);\n \n+\tif (is_64k_pagesize)\n+\t\ttopts.data_size_in = sizeof(pkt_v4) - 1;\n+\telse\n+\t\ttopts.data_size_in = sizeof(pkt_v4);\n+\n \terr = bpf_prog_test_load(file, BPF_PROG_TYPE_XDP, &obj, &prog_fd);\n \tif (!ASSERT_OK(err, \"test_xdp_adjust_tail_grow\"))\n \t\treturn;\n@@ -208,7 +212,7 @@ static void test_xdp_adjust_frags_tail_shrink(void)\n \tbpf_object__close(obj);\n }\n \n-static void test_xdp_adjust_frags_tail_grow(void)\n+static void test_xdp_adjust_frags_tail_grow_4k(void)\n {\n \tconst char *file = \"./test_xdp_adjust_tail_grow.bpf.o\";\n \t__u32 exp_size;\n@@ -279,16 +283,93 @@ static void test_xdp_adjust_frags_tail_grow(void)\n \tbpf_object__close(obj);\n }\n \n+static void test_xdp_adjust_frags_tail_grow_64k(void)\n+{\n+\tconst char *file = \"./test_xdp_adjust_tail_grow.bpf.o\";\n+\t__u32 exp_size;\n+\tstruct bpf_program *prog;\n+\tstruct bpf_object *obj;\n+\tint err, i, prog_fd;\n+\t__u8 *buf;\n+\tLIBBPF_OPTS(bpf_test_run_opts, topts);\n+\n+\tobj = bpf_object__open(file);\n+\tif (libbpf_get_error(obj))\n+\t\treturn;\n+\n+\tprog = bpf_object__next_program(obj, NULL);\n+\tif (bpf_object__load(obj))\n+\t\tgoto out;\n+\n+\tprog_fd = bpf_program__fd(prog);\n+\n+\tbuf = malloc(262144);\n+\tif (!ASSERT_OK_PTR(buf, \"alloc buf 256Kb\"))\n+\t\tgoto out;\n+\n+\t/* Test case add 10 bytes to last frag */\n+\tmemset(buf, 1, 262144);\n+\texp_size = 90000 + 10;\n+\n+\ttopts.data_in = buf;\n+\ttopts.data_out = buf;\n+\ttopts.data_size_in = 90000;\n+\ttopts.data_size_out = 262144;\n+\terr = bpf_prog_test_run_opts(prog_fd, &topts);\n+\n+\tASSERT_OK(err, \"90Kb+10b\");\n+\tASSERT_EQ(topts.retval, XDP_TX, \"90Kb+10b retval\");\n+\tASSERT_EQ(topts.data_size_out, exp_size, \"90Kb+10b size\");\n+\n+\tfor (i = 0; i < 90000; i++) {\n+\t\tif (buf[i] != 1)\n+\t\t\tASSERT_EQ(buf[i], 1, \"90Kb+10b-old\");\n+\t}\n+\n+\tfor (i = 90000; i < 90010; i++) {\n+\t\tif (buf[i] != 0)\n+\t\t\tASSERT_EQ(buf[i], 0, \"90Kb+10b-new\");\n+\t}\n+\n+\tfor (i = 90010; i < 262144; i++) {\n+\t\tif (buf[i] != 1)\n+\t\t\tASSERT_EQ(buf[i], 1, \"90Kb+10b-untouched\");\n+\t}\n+\n+\t/* Test a too large grow */\n+\tmemset(buf, 1, 262144);\n+\texp_size = 90001;\n+\n+\ttopts.data_in = topts.data_out = buf;\n+\ttopts.data_size_in = 90001;\n+\ttopts.data_size_out = 262144;\n+\terr = bpf_prog_test_run_opts(prog_fd, &topts);\n+\n+\tASSERT_OK(err, \"90Kb+10b\");\n+\tASSERT_EQ(topts.retval, XDP_DROP, \"90Kb+10b retval\");\n+\tASSERT_EQ(topts.data_size_out, exp_size, \"90Kb+10b size\");\n+\n+\tfree(buf);\n+out:\n+\tbpf_object__close(obj);\n+}\n+\n void test_xdp_adjust_tail(void)\n {\n+\tint page_size = getpagesize();\n+\n \tif (test__start_subtest(\"xdp_adjust_tail_shrink\"))\n \t\ttest_xdp_adjust_tail_shrink();\n \tif (test__start_subtest(\"xdp_adjust_tail_grow\"))\n-\t\ttest_xdp_adjust_tail_grow();\n+\t\ttest_xdp_adjust_tail_grow(page_size == 65536);\n \tif (test__start_subtest(\"xdp_adjust_tail_grow2\"))\n \t\ttest_xdp_adjust_tail_grow2();\n \tif (test__start_subtest(\"xdp_adjust_frags_tail_shrink\"))\n \t\ttest_xdp_adjust_frags_tail_shrink();\n-\tif (test__start_subtest(\"xdp_adjust_frags_tail_grow\"))\n-\t\ttest_xdp_adjust_frags_tail_grow();\n+\tif (test__start_subtest(\"xdp_adjust_frags_tail_grow\")) {\n+\t\tif (page_size == 65536)\n+\t\t\ttest_xdp_adjust_frags_tail_grow_64k();\n+\t\telse\n+\t\t\ttest_xdp_adjust_frags_tail_grow_4k();\n+\t}\n }\ndiff --git a/tools/testing/selftests/bpf/progs/test_xdp_adjust_tail_grow.c b/tools/testing/selftests/bpf/progs/test_xdp_adjust_tail_grow.c\nindex dc74d8cf9e3f..93d55a2ca340 100644\n--- a/tools/testing/selftests/bpf/progs/test_xdp_adjust_tail_grow.c\n+++ b/tools/testing/selftests/bpf/progs/test_xdp_adjust_tail_grow.c\n@@ -19,7 +19,9 @@ int _xdp_adjust_tail_grow(struct xdp_md *xdp)\n \t/* Data length determine test case */\n \n \tif (data_len == 54) { /* sizeof(pkt_v4) */\n-\t\toffset = 4096; /* test too large offset */\n+\t\toffset = 4096; /* test too large offset, 4k page size */\n+\t} else if (data_len == 53) { /* sizeof(pkt_v4) - 1 */\n+\t\toffset = 65536; /* test too large offset, 64k page size */\n \t} else if (data_len == 74) { /* sizeof(pkt_v6) */\n \t\toffset = 40;\n \t} else if (data_len == 64) {\n@@ -31,6 +33,10 @@ int _xdp_adjust_tail_grow(struct xdp_md *xdp)\n \t\toffset = 10;\n \t} else if (data_len == 9001) {\n \t\toffset = 4096;\n+\t} else if (data_len == 90000) {\n+\t\toffset = 10;\n+\t} else if (data_len == 90001) {\n+\t\toffset = 65536;\n \t} else {\n \t\treturn XDP_ABORTED; /* No matching test */\n \t}\n", + "prefixes": [ + "bpf-next", + "v2", + "1/3" + ] +} diff --git a/tests/data/test_github_sync.test_sync_patches_pr_summary_success/patch-14114774.json b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/patch-14114774.json new file mode 100644 index 0000000..1359ff0 --- /dev/null +++ b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/patch-14114774.json @@ -0,0 +1,92 @@ +{ + "id": 14114774, + "url": "https://patchwork.test/api/1.1/patches/14114774/", + "web_url": "https://patchwork.test/project/netdevbpf/patch/20250611171529.2034330-1-yonghong.song@linux.dev/", + "project": { + "id": 399, + "url": "https://patchwork.test/api/1.1/projects/399/", + "name": "Netdev + BPF", + "link_name": "netdevbpf", + "list_id": "bpf.vger.kernel.org", + "list_email": "bpf@vger.kernel.org", + "web_url": "", + "scm_url": "", + "webscm_url": "" + }, + "msgid": "<20250611171529.2034330-1-yonghong.song@linux.dev>", + "date": "2025-06-11T17:15:29", + "name": "[bpf-next,v2,2/3] selftests/bpf: Fix two net related test failures with 64K page size", + "commit_ref": null, + "pull_url": null, + "state": "changes-requested", + "archived": false, + "hash": "3734274f90b6282e0c574a9ac2c9bda37ef5d6a0", + "submitter": { + "id": 210263, + "url": "https://patchwork.test/api/1.1/people/210263/", + "name": "Yonghong Song", + "email": "yonghong.song@linux.dev" + }, + "delegate": { + "id": 121173, + "url": "https://patchwork.test/api/1.1/users/121173/", + "username": "bpf", + "first_name": "BPF", + "last_name": "", + "email": "bpf@iogearbox.net" + }, + "mbox": "https://patchwork.test/project/netdevbpf/patch/20250611171529.2034330-1-yonghong.song@linux.dev/mbox/", + "series": [ + { + "id": 970968, + "url": "https://patchwork.test/api/1.1/series/970968/", + "web_url": "https://patchwork.test/project/netdevbpf/list/?series=970968", + "date": "2025-06-11T17:15:19", + "name": "bpf: Fix a few test failures with 64K page size", + "version": 2, + "mbox": "https://patchwork.test/series/970968/mbox/" + } + ], + "comments": "https://patchwork.test/api/patches/14114774/comments/", + "check": "warning", + "checks": "https://patchwork.test/api/patches/14114774/checks/", + "tags": {}, + "headers": { + "Received": [ + "from 66-220-144-178.mail-mxout.facebook.com\n (66-220-144-178.mail-mxout.facebook.com [66.220.144.178])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id 774B0137C37\n\tfor ; Wed, 11 Jun 2025 17:15:42 +0000 (UTC)", + "by devvm16039.vll0.facebook.com (Postfix, from userid 128203)\n\tid E0EAE9680C54; Wed, 11 Jun 2025 10:15:29 -0700 (PDT)" + ], + "Authentication-Results": [ + "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=66.220.144.178", + "smtp.subspace.kernel.org;\n dmarc=fail (p=none dis=none) header.from=linux.dev", + "smtp.subspace.kernel.org;\n spf=fail smtp.mailfrom=linux.dev" + ], + "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1749662145; cv=none;\n b=H1WJsmTVYK/pQCrvjiSyGJXScsH2kh3zzJFhoBu4l4Ez7VwqeePNmGMkPc4qMYe6d13tnC0uhXAY5UfuHykgA5UcOO9huji7LcDqCgHku0lcmr3CVs2hkFaHdwk2A2Gb/EdvUbXMH6girJSNofJtdgYqwCLL+pKaJKUiw4qhaIQ=", + "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1749662145; c=relaxed/simple;\n\tbh=jLp9gVJ6J82pb2dajEsxJQ0BNmXZ932mE7BpXCb6MY0=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=qv5p8hJPAywS1NwNCBhUoayN3awlHOs2ggVMu0kPzIkBSH14hvIaARYMb8nkEzENSjCLotoab99Q23TZ5FnukzQICrFiT/80rhuUu15sifa48WTku4pNsCjVIA6yT3TGI0iSY3iHYP0j0stnJfM6VWWDXyVFpi44GhzrLM9Hv5A=", + "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dmarc=fail (p=none dis=none) header.from=linux.dev;\n spf=fail smtp.mailfrom=linux.dev; arc=none smtp.client-ip=66.220.144.178", + "From": "Yonghong Song ", + "To": "bpf@vger.kernel.org", + "Cc": "Alexei Starovoitov ,\n\tAndrii Nakryiko ,\n\tDaniel Borkmann ,\n\tkernel-team@fb.com,\n\tMartin KaFai Lau ", + "Subject": "[PATCH bpf-next v2 2/3] selftests/bpf: Fix two net related test\n failures with 64K page size", + "Date": "Wed, 11 Jun 2025 10:15:29 -0700", + "Message-ID": "<20250611171529.2034330-1-yonghong.song@linux.dev>", + "X-Mailer": "git-send-email 2.47.1", + "In-Reply-To": "<20250611171519.2033193-1-yonghong.song@linux.dev>", + "References": "<20250611171519.2033193-1-yonghong.song@linux.dev>", + "Precedence": "bulk", + "X-Mailing-List": "bpf@vger.kernel.org", + "List-Id": "", + "List-Subscribe": "", + "List-Unsubscribe": "", + "MIME-Version": "1.0", + "Content-Transfer-Encoding": "quoted-printable", + "X-Patchwork-Delegate": "bpf@iogearbox.net" + }, + "content": "When running BPF selftests on arm64 with a 64K page size, I encountered\nthe following two test failures:\n sockmap_basic/sockmap skb_verdict change tail:FAIL\n tc_change_tail:FAIL\n\nWith further debugging, I identified the root cause in the following\nkernel code within __bpf_skb_change_tail():\n\n u32 max_len = BPF_SKB_MAX_LEN;\n u32 min_len = __bpf_skb_min_len(skb);\n int ret;\n\n if (unlikely(flags || new_len > max_len || new_len < min_len))\n return -EINVAL;\n\nWith a 4K page size, new_len = 65535 and max_len = 16064, the function\nreturns -EINVAL. However, With a 64K page size, max_len increases to\n261824, allowing execution to proceed further in the function. This is\nbecause BPF_SKB_MAX_LEN scales with the page size and larger page sizes\nresult in higher max_len values.\n\nUpdating the new_len parameter in both tests from 65535 to 256K (0x40000)\nresolves the failures.\n\nSigned-off-by: Yonghong Song \n---\n tools/testing/selftests/bpf/progs/test_sockmap_change_tail.c | 5 ++++-\n tools/testing/selftests/bpf/progs/test_tc_change_tail.c | 5 ++++-\n 2 files changed, 8 insertions(+), 2 deletions(-)", + "diff": "diff --git a/tools/testing/selftests/bpf/progs/test_sockmap_change_tail.c b/tools/testing/selftests/bpf/progs/test_sockmap_change_tail.c\nindex 2796dd8545eb..e4554ef05441 100644\n--- a/tools/testing/selftests/bpf/progs/test_sockmap_change_tail.c\n+++ b/tools/testing/selftests/bpf/progs/test_sockmap_change_tail.c\n@@ -3,6 +3,9 @@\n #include \n #include \n \n+#define PAGE_SIZE 65536 /* make it work on 64K page arches */\n+#define BPF_SKB_MAX_LEN (PAGE_SIZE << 2)\n+\n struct {\n \t__uint(type, BPF_MAP_TYPE_SOCKMAP);\n \t__uint(max_entries, 1);\n@@ -31,7 +34,7 @@ int prog_skb_verdict(struct __sk_buff *skb)\n \t\tchange_tail_ret = bpf_skb_change_tail(skb, skb->len + 1, 0);\n \t\treturn SK_PASS;\n \t} else if (data[0] == 'E') { /* Error */\n-\t\tchange_tail_ret = bpf_skb_change_tail(skb, 65535, 0);\n+\t\tchange_tail_ret = bpf_skb_change_tail(skb, BPF_SKB_MAX_LEN, 0);\n \t\treturn SK_PASS;\n \t}\n \treturn SK_PASS;\ndiff --git a/tools/testing/selftests/bpf/progs/test_tc_change_tail.c b/tools/testing/selftests/bpf/progs/test_tc_change_tail.c\nindex 28edafe803f0..47670bbd1766 100644\n--- a/tools/testing/selftests/bpf/progs/test_tc_change_tail.c\n+++ b/tools/testing/selftests/bpf/progs/test_tc_change_tail.c\n@@ -7,6 +7,9 @@\n #include \n #include \n \n+#define PAGE_SIZE 65536 /* make it work on 64K page arches */\n+#define BPF_SKB_MAX_LEN (PAGE_SIZE << 2)\n+\n long change_tail_ret = 1;\n \n static __always_inline struct iphdr *parse_ip_header(struct __sk_buff *skb, int *ip_proto)\n@@ -94,7 +97,7 @@ int change_tail(struct __sk_buff *skb)\n \t\t\tbpf_skb_change_tail(skb, len, 0);\n \t\treturn TCX_PASS;\n \t} else if (payload[0] == 'E') { /* Error */\n-\t\tchange_tail_ret = bpf_skb_change_tail(skb, 65535, 0);\n+\t\tchange_tail_ret = bpf_skb_change_tail(skb, BPF_SKB_MAX_LEN, 0);\n \t\treturn TCX_PASS;\n \t} else if (payload[0] == 'Z') { /* Zero */\n \t\tchange_tail_ret = bpf_skb_change_tail(skb, 0, 0);\n", + "prefixes": [ + "bpf-next", + "v2", + "2/3" + ] +} diff --git a/tests/data/test_github_sync.test_sync_patches_pr_summary_success/patch-14114775.json b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/patch-14114775.json new file mode 100644 index 0000000..62cc840 --- /dev/null +++ b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/patch-14114775.json @@ -0,0 +1,92 @@ +{ + "id": 14114775, + "url": "https://patchwork.test/api/1.1/patches/14114775/", + "web_url": "https://patchwork.test/project/netdevbpf/patch/20250611171535.2034440-1-yonghong.song@linux.dev/", + "project": { + "id": 399, + "url": "https://patchwork.test/api/1.1/projects/399/", + "name": "Netdev + BPF", + "link_name": "netdevbpf", + "list_id": "bpf.vger.kernel.org", + "list_email": "bpf@vger.kernel.org", + "web_url": "", + "scm_url": "", + "webscm_url": "" + }, + "msgid": "<20250611171535.2034440-1-yonghong.song@linux.dev>", + "date": "2025-06-11T17:15:34", + "name": "[bpf-next,v2,3/3] selftests/bpf: Fix xdp_do_redirect failure with 64KB page size", + "commit_ref": null, + "pull_url": null, + "state": "changes-requested", + "archived": false, + "hash": "70c808de4bdae179786cead1c8e1ce36458e2f6b", + "submitter": { + "id": 210263, + "url": "https://patchwork.test/api/1.1/people/210263/", + "name": "Yonghong Song", + "email": "yonghong.song@linux.dev" + }, + "delegate": { + "id": 121173, + "url": "https://patchwork.test/api/1.1/users/121173/", + "username": "bpf", + "first_name": "BPF", + "last_name": "", + "email": "bpf@iogearbox.net" + }, + "mbox": "https://patchwork.test/project/netdevbpf/patch/20250611171535.2034440-1-yonghong.song@linux.dev/mbox/", + "series": [ + { + "id": 970968, + "url": "https://patchwork.test/api/1.1/series/970968/", + "web_url": "https://patchwork.test/project/netdevbpf/list/?series=970968", + "date": "2025-06-11T17:15:19", + "name": "bpf: Fix a few test failures with 64K page size", + "version": 2, + "mbox": "https://patchwork.test/series/970968/mbox/" + } + ], + "comments": "https://patchwork.test/api/patches/14114775/comments/", + "check": "warning", + "checks": "https://patchwork.test/api/patches/14114775/checks/", + "tags": {}, + "headers": { + "Received": [ + "from 69-171-232-181.mail-mxout.facebook.com\n (69-171-232-181.mail-mxout.facebook.com [69.171.232.181])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id E26431CD208\n\tfor ; Wed, 11 Jun 2025 17:15:48 +0000 (UTC)", + "by devvm16039.vll0.facebook.com (Postfix, from userid 128203)\n\tid 056A59680C77; Wed, 11 Jun 2025 10:15:35 -0700 (PDT)" + ], + "Authentication-Results": [ + "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=69.171.232.181", + "smtp.subspace.kernel.org;\n dmarc=fail (p=none dis=none) header.from=linux.dev", + "smtp.subspace.kernel.org;\n spf=fail smtp.mailfrom=linux.dev" + ], + "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1749662150; cv=none;\n b=EX6Jq8P3VFj4+k08zD4Oofu4WRtyxpk8xW4t2wI4uqCJfR2NQJU7YG9PDDy3yng2pN65VDv62grnWacaQhSIcayEqmPlXoVg+jpLPNrZSgIlGFW9pvAo+C+V2a0TYX+vcTsTfgaHiRPKKbq/N5LZAnKwmEHjeaoijrJrJKoLKnY=", + "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1749662150; c=relaxed/simple;\n\tbh=jJgT63k4r+/mDJ1wI8n6mvKTyi6x10RwgW4AYPOjMNU=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=jny55tY3BEMQKCxQxa4mEz4nigGmYoOxdH7UgG0mw4uznXEBm0duBjpyNvoSLxILvFCCsSR7ualBa7M3L9IQYqhWjM9FS1Y0KslCdawLFNHqNgeCGZjUK9JPlvu2wVZtJQpkH6koy/Zkr3x1Sg4OIyWpB7jtsbWKyTQU6s+GaPs=", + "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dmarc=fail (p=none dis=none) header.from=linux.dev;\n spf=fail smtp.mailfrom=linux.dev; arc=none smtp.client-ip=69.171.232.181", + "From": "Yonghong Song ", + "To": "bpf@vger.kernel.org", + "Cc": "Alexei Starovoitov ,\n\tAndrii Nakryiko ,\n\tDaniel Borkmann ,\n\tkernel-team@fb.com,\n\tMartin KaFai Lau ", + "Subject": "[PATCH bpf-next v2 3/3] selftests/bpf: Fix xdp_do_redirect failure\n with 64KB page size", + "Date": "Wed, 11 Jun 2025 10:15:34 -0700", + "Message-ID": "<20250611171535.2034440-1-yonghong.song@linux.dev>", + "X-Mailer": "git-send-email 2.47.1", + "In-Reply-To": "<20250611171519.2033193-1-yonghong.song@linux.dev>", + "References": "<20250611171519.2033193-1-yonghong.song@linux.dev>", + "Precedence": "bulk", + "X-Mailing-List": "bpf@vger.kernel.org", + "List-Id": "", + "List-Subscribe": "", + "List-Unsubscribe": "", + "MIME-Version": "1.0", + "Content-Transfer-Encoding": "quoted-printable", + "X-Patchwork-Delegate": "bpf@iogearbox.net" + }, + "content": "On arm64 with 64KB page size, the selftest xdp_do_redirect failed like\nbelow:\n ...\n test_xdp_do_redirect:PASS:pkt_count_tc 0 nsec\n test_max_pkt_size:PASS:prog_run_max_size 0 nsec\n test_max_pkt_size:FAIL:prog_run_too_big unexpected prog_run_too_big: actual -28 != expected -22\n\nWith 64KB page size, the xdp frame size will be much bigger so\nthe existing test will fail.\n\nAdjust various parameters so the test can also work on 64K page size.\n\nSigned-off-by: Yonghong Song \n---\n .../selftests/bpf/prog_tests/xdp_do_redirect.c | 13 +++++++++++--\n 1 file changed, 11 insertions(+), 2 deletions(-)", + "diff": "diff --git a/tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c b/tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c\nindex 7dac044664ac..dd34b0cc4b4e 100644\n--- a/tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c\n+++ b/tools/testing/selftests/bpf/prog_tests/xdp_do_redirect.c\n@@ -66,16 +66,25 @@ static int attach_tc_prog(struct bpf_tc_hook *hook, int fd)\n #else\n #define MAX_PKT_SIZE 3408\n #endif\n+\n+#define PAGE_SIZE_4K 4096\n+#define PAGE_SIZE_64K 65536\n+\n static void test_max_pkt_size(int fd)\n {\n-\tchar data[MAX_PKT_SIZE + 1] = {};\n+\tchar data[PAGE_SIZE_64K + 1] = {};\n \tint err;\n \tDECLARE_LIBBPF_OPTS(bpf_test_run_opts, opts,\n \t\t\t .data_in = &data,\n-\t\t\t .data_size_in = MAX_PKT_SIZE,\n \t\t\t .flags = BPF_F_TEST_XDP_LIVE_FRAMES,\n \t\t\t .repeat = 1,\n \t\t);\n+\n+\tif (getpagesize() == PAGE_SIZE_64K)\n+\t\topts.data_size_in = MAX_PKT_SIZE + PAGE_SIZE_64K - PAGE_SIZE_4K;\n+\telse\n+\t\topts.data_size_in = MAX_PKT_SIZE;\n+\n \terr = bpf_prog_test_run_opts(fd, &opts);\n \tASSERT_OK(err, \"prog_run_max_size\");\n \n", + "prefixes": [ + "bpf-next", + "v2", + "3/3" + ] +} diff --git a/tests/data/test_github_sync.test_sync_patches_pr_summary_success/patch-14114777.json b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/patch-14114777.json new file mode 100644 index 0000000..3d7d10f --- /dev/null +++ b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/patch-14114777.json @@ -0,0 +1,96 @@ +{ + "id": 14114777, + "url": "https://patchwork.test/api/1.1/patches/14114777/", + "web_url": "https://patchwork.test/project/netdevbpf/patch/20250611-rcu-fix-task_cls_state-v3-1-3d30e1de753f@posteo.net/", + "project": { + "id": 399, + "url": "https://patchwork.test/api/1.1/projects/399/", + "name": "Netdev + BPF", + "link_name": "netdevbpf", + "list_id": "bpf.vger.kernel.org", + "list_email": "bpf@vger.kernel.org", + "web_url": "", + "scm_url": "", + "webscm_url": "" + }, + "msgid": "<20250611-rcu-fix-task_cls_state-v3-1-3d30e1de753f@posteo.net>", + "date": "2025-06-11T17:20:43", + "name": "[bpf-next,v3] net: Fix RCU usage in task_cls_state() for BPF programs", + "commit_ref": "7f12c33850482521c961c5c15a50ebe9b9a88d1e", + "pull_url": null, + "state": "accepted", + "archived": false, + "hash": "fb8bc5714a26b9ad4011597046c855b5a4857807", + "submitter": { + "id": 211324, + "url": "https://patchwork.test/api/1.1/people/211324/", + "name": "Charalampos Mitrodimas", + "email": "charmitro@posteo.net" + }, + "delegate": { + "id": 121173, + "url": "https://patchwork.test/api/1.1/users/121173/", + "username": "bpf", + "first_name": "BPF", + "last_name": "", + "email": "bpf@iogearbox.net" + }, + "mbox": "https://patchwork.test/project/netdevbpf/patch/20250611-rcu-fix-task_cls_state-v3-1-3d30e1de753f@posteo.net/mbox/", + "series": [ + { + "id": 970970, + "url": "https://patchwork.test/api/1.1/series/970970/", + "web_url": "https://patchwork.test/project/netdevbpf/list/?series=970970", + "date": "2025-06-11T17:20:43", + "name": "[bpf-next,v3] net: Fix RCU usage in task_cls_state() for BPF programs", + "version": 3, + "mbox": "https://patchwork.test/series/970970/mbox/" + } + ], + "comments": "https://patchwork.test/api/patches/14114777/comments/", + "check": "warning", + "checks": "https://patchwork.test/api/patches/14114777/checks/", + "tags": {}, + "headers": { + "Received": [ + "from mout02.posteo.de (mout02.posteo.de [185.67.36.66])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id EACDA222561\n\tfor ; Wed, 11 Jun 2025 17:21:08 +0000 (UTC)", + "from submission (posteo.de [185.67.36.169])\n\tby mout02.posteo.de (Postfix) with ESMTPS id 5B212240101\n\tfor ; Wed, 11 Jun 2025 19:21:07 +0200 (CEST)", + "from customer (localhost [127.0.0.1])\n\tby submission (posteo.de) with ESMTPSA id 4bHXW323xjz9rxQ;\n\tWed, 11 Jun 2025 19:21:03 +0200 (CEST)" + ], + "Authentication-Results": [ + "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=185.67.36.66", + "smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=posteo.net", + "smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=posteo.net", + "smtp.subspace.kernel.org;\n\tdkim=pass (3072-bit key) header.d=posteo.net header.i=@posteo.net\n header.b=\"A5Md52u3\"" + ], + "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1749662471; cv=none;\n b=qnOH5IEg/mKwGuevTWBRHpoZXI8EjsMxKdNg7Nw1sWc7U3KWQDEpi18dlZ2vuKm6ZWfrIy+qBjG2SXrX95fTYD7cEtSX6fMkdC4+0SX86tU6HV4FqEWWVR8JH3G3shzOpvYCHwPcvHhoRS8zvNc+aevrTlNeG/92bMyjgp9zysw=", + "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1749662471; c=relaxed/simple;\n\tbh=u5Kk1jfvzFrOwlCXwYxoep/9dBDPOwrOQVQdE3Geobw=;\n\th=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc;\n b=C9Woqk2GWImZm18X++r/v4f+Tz/54iG9LqN25UikQcgsMFIukmRLqJQg90gSjQ5bUQV24yO0UtWDI+MiwtjV3dnD+OC1F71HTTF8tTGm2zDTuPFor1ACjLJQc6FeXKuHNgKT/hyt7Ku/CbRtHN+FLzcARj1WeYpRKAn8t6xKGBY=", + "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=posteo.net;\n spf=pass smtp.mailfrom=posteo.net;\n dkim=pass (3072-bit key) header.d=posteo.net header.i=@posteo.net\n header.b=A5Md52u3; arc=none smtp.client-ip=185.67.36.66", + "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/simple; d=posteo.net;\n\ts=1984.ea087b; t=1749662467;\n\tbh=u5Kk1jfvzFrOwlCXwYxoep/9dBDPOwrOQVQdE3Geobw=;\n\th=From:Date:Subject:MIME-Version:Content-Type:\n\t Content-Transfer-Encoding:Message-Id:To:Cc:From;\n\tb=A5Md52u3STlkO+A8jTT+13k1GA3nD1EBgT6khcCenX/tpCDQSURx9JPPCVEBBHfXb\n\t eZzOT1HsHBVaGUqYPzH02x4srcEGZer2OgO0WGiv6/dueoIu4mcT8Pu6NXpP2Ndhxq\n\t yq5/9d83/1d0Qz5W58Oqj7yjbCwIcjq3oL1yaIx28k1hClgRVafa/GdYJVtb2nmOhJ\n\t GlPPnpmIArGpb0ls3pFhioBSjphuortNfRRXyibVYOozphg/KxuQ5k+8OXh0QMWoOC\n\t TjYVvv62gb/mCO8W+dpH3oPPUOcGi2Mx++WS/ldb4SLfBDidrseF7OVhgYMvi5pFAp\n\t xQRM30E1zv/K7YuEcXOb+nQr8jaHLir+p64PvyIH3QZN0B8nfE7Gpf8QoupLV+wDNb\n\t V8c4lRb+/aLqXNaqd8oAMP45JlSvR6nfEtEyHEinPQMeJB5aemwbxl1SgZYFLDjoYD\n\t kWR2mzs87p7pGq9RKP419oYEJ8aMqwSALe52YeKvIpFpxcxQUOP", + "From": "Charalampos Mitrodimas ", + "Date": "Wed, 11 Jun 2025 17:20:43 +0000", + "Subject": "[PATCH bpf-next v3] net: Fix RCU usage in task_cls_state() for BPF\n programs", + "Precedence": "bulk", + "X-Mailing-List": "bpf@vger.kernel.org", + "List-Id": "", + "List-Subscribe": "", + "List-Unsubscribe": "", + "MIME-Version": "1.0", + "Content-Type": "text/plain; charset=\"utf-8\"", + "Content-Transfer-Encoding": "7bit", + "Message-Id": "<20250611-rcu-fix-task_cls_state-v3-1-3d30e1de753f@posteo.net>", + "X-B4-Tracking": "v=1; b=H4sIAOq6SWgC/4XNQQ6CMBAF0KuQrq1ppxWIK+9hDCllkEZDSac2G\n sLdLax0YVz+yf9vZkYYHBI7FjMLmBw5P+agdgWzgxmvyF2XMwMBB1GKmgf74L178mjo1tg7NRR\n NRC6wq1SvVdVJZHk8BcytDT5fch4cRR9e258k1+tfMkkuOZi11upSqPY0eYro9yNGtpoJPhwpf\n zqQHWmq3oKuQYH5cpZleQNGtF7QBQEAAA==", + "X-Change-ID": "20250608-rcu-fix-task_cls_state-0ed73f437d1e", + "To": "\"David S. Miller\" ,\n Eric Dumazet , Jakub Kicinski ,\n Paolo Abeni , Simon Horman ,\n Martin KaFai Lau ,\n Daniel Borkmann ,\n John Fastabend ,\n Alexei Starovoitov , Andrii Nakryiko ,\n Eduard Zingerman , Song Liu ,\n Yonghong Song , KP Singh ,\n Stanislav Fomichev , Hao Luo ,\n Jiri Olsa , Feng Yang ,\n Tejun Heo ", + "Cc": "netdev@vger.kernel.org, linux-kernel@vger.kernel.org,\n bpf@vger.kernel.org, syzbot+b4169a1cfb945d2ed0ec@syzkaller.appspotmail.com,\n Charalampos Mitrodimas ", + "X-Developer-Signature": "v=1; a=ed25519-sha256; t=1749662443; l=2729;\n i=charmitro@posteo.net; s=20250526; h=from:subject:message-id;\n bh=u5Kk1jfvzFrOwlCXwYxoep/9dBDPOwrOQVQdE3Geobw=;\n b=cOJU/Y97B/mIsiD6ycUzLbHOj+hDqh9honeXQ3bF5ZN1FpCw/P9xFzMlBjxDgS6XhO9jdIj0R\n BW5omZ1EtlGBMPPQfoVetlQvPuxjKIUWGThuj0Mz8r5uXn4WqXjI4A4", + "X-Developer-Key": "i=charmitro@posteo.net; a=ed25519;\n pk=PNHEh5o1dcr5kfKoZhfwdsfm3CxVfRje7vFYKIW0Mp4=", + "X-Patchwork-Delegate": "bpf@iogearbox.net" + }, + "content": "The commit ee971630f20f (\"bpf: Allow some trace helpers for all prog\ntypes\") made bpf_get_cgroup_classid_curr helper available to all BPF\nprogram types, not just networking programs.\n\nThis helper calls __task_get_classid() which internally calls\ntask_cls_state() requiring rcu_read_lock_bh_held(). This works in\nnetworking/tc context where RCU BH is held, but triggers an RCU\nwarning when called from other contexts like BPF syscall programs that\nrun under rcu_read_lock_trace():\n\n WARNING: suspicious RCU usage\n 6.15.0-rc4-syzkaller-g079e5c56a5c4 #0 Not tainted\n -----------------------------\n net/core/netclassid_cgroup.c:24 suspicious rcu_dereference_check() usage!\n\nFix this by also accepting rcu_read_lock_held() and\nrcu_read_lock_trace_held() as valid RCU contexts in the\ntask_cls_state() function. This ensures the helper works correctly in\nall RCU contexts where it might be called, regular RCU, RCU BH (for\nnetworking), and RCU trace (for BPF syscall programs).\n\nReported-by: syzbot+b4169a1cfb945d2ed0ec@syzkaller.appspotmail.com\nCloses: https://syzkaller.appspot.com/bug?extid=b4169a1cfb945d2ed0ec\nFixes: ee971630f20f (\"bpf: Allow some trace helpers for all prog types\")\nSigned-off-by: Charalampos Mitrodimas \n---\nChanges in v3:\n- Add rcu_read_lock_held() check as well \n- Link to v2: https://lore.kernel.org/r/20250611-rcu-fix-task_cls_state-v2-1-1a7fc248232a@posteo.net\n\nChanges in v2:\n- Fix RCU usage in task_cls_state() instead of BPF helper\n- Add rcu_read_lock_trace_held() check to accept trace RCU as valid\n context\n- Drop the approach of using task_cls_classid() which has in_interrupt()\n check\n- Link to v1: https://lore.kernel.org/r/20250608-rcu-fix-task_cls_state-v1-1-2a2025b4603b@posteo.net\n---\n net/core/netclassid_cgroup.c | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\n\n---\nbase-commit: 079e5c56a5c41d285068939ff7b0041ab10386fa\nchange-id: 20250608-rcu-fix-task_cls_state-0ed73f437d1e\n\nBest regards,", + "diff": "diff --git a/net/core/netclassid_cgroup.c b/net/core/netclassid_cgroup.c\nindex d22f0919821e931fbdedf5a8a7a2998d59d73978..dff66d8fb325d28bb15f42641b9ec738b0022353 100644\n--- a/net/core/netclassid_cgroup.c\n+++ b/net/core/netclassid_cgroup.c\n@@ -21,7 +21,9 @@ static inline struct cgroup_cls_state *css_cls_state(struct cgroup_subsys_state\n struct cgroup_cls_state *task_cls_state(struct task_struct *p)\n {\n \treturn css_cls_state(task_css_check(p, net_cls_cgrp_id,\n-\t\t\t\t\t rcu_read_lock_bh_held()));\n+\t\t\t\t\t rcu_read_lock_held() ||\n+\t\t\t\t\t rcu_read_lock_bh_held() ||\n+\t\t\t\t\t rcu_read_lock_trace_held()));\n }\n EXPORT_SYMBOL_GPL(task_cls_state);\n \n", + "prefixes": [ + "bpf-next", + "v3" + ] +} diff --git a/tests/data/test_github_sync.test_sync_patches_pr_summary_success/relevant-subjects-20250610.json b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/relevant-subjects-20250610.json new file mode 100644 index 0000000..b8bea12 --- /dev/null +++ b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/relevant-subjects-20250610.json @@ -0,0 +1,164 @@ +[ + { + "id": 14114605, + "url": "https://patchwork.test/api/1.1/patches/14114605/", + "web_url": "https://patchwork.test/project/netdevbpf/patch/20250611154859.259682-1-chen.dylane@linux.dev/", + "project": { + "id": 399, + "url": "https://patchwork.test/api/1.1/projects/399/", + "name": "Netdev + BPF", + "link_name": "netdevbpf", + "list_id": "bpf.vger.kernel.org", + "list_email": "bpf@vger.kernel.org", + "web_url": "", + "scm_url": "", + "webscm_url": "" + }, + "msgid": "<20250611154859.259682-1-chen.dylane@linux.dev>", + "date": "2025-06-11T15:48:58", + "name": "[bpf-next] bpf: clear user buf when bpf_d_path failed", + "commit_ref": null, + "pull_url": null, + "state": "new", + "archived": false, + "hash": "ecb10e6ecea01d3f770e4d08eb251179b0f9a98b", + "submitter": { + "id": 216065, + "url": "https://patchwork.test/api/1.1/people/216065/", + "name": "Tao Chen", + "email": "chen.dylane@linux.dev" + }, + "delegate": { + "id": 121173, + "url": "https://patchwork.test/api/1.1/users/121173/", + "username": "bpf", + "first_name": "BPF", + "last_name": "", + "email": "bpf@iogearbox.net" + }, + "mbox": "https://patchwork.test/project/netdevbpf/patch/20250611154859.259682-1-chen.dylane@linux.dev/mbox/", + "series": [ + { + "id": 970926, + "url": "https://patchwork.test/api/1.1/series/970926/", + "web_url": "https://patchwork.test/project/netdevbpf/list/?series=970926", + "date": "2025-06-11T15:48:58", + "name": "[bpf-next] bpf: clear user buf when bpf_d_path failed", + "version": 1, + "mbox": "https://patchwork.test/series/970926/mbox/" + } + ], + "comments": "https://patchwork.test/api/patches/14114605/comments/", + "check": "success", + "checks": "https://patchwork.test/api/patches/14114605/checks/", + "tags": {} + }, + { + "id": 14114774, + "url": "https://patchwork.test/api/1.1/patches/14114774/", + "web_url": "https://patchwork.test/project/netdevbpf/patch/20250611171529.2034330-1-yonghong.song@linux.dev/", + "project": { + "id": 399, + "url": "https://patchwork.test/api/1.1/projects/399/", + "name": "Netdev + BPF", + "link_name": "netdevbpf", + "list_id": "bpf.vger.kernel.org", + "list_email": "bpf@vger.kernel.org", + "web_url": "", + "scm_url": "", + "webscm_url": "" + }, + "msgid": "<20250611171529.2034330-1-yonghong.song@linux.dev>", + "date": "2025-06-11T17:15:29", + "name": "[bpf-next,v2,2/3] selftests/bpf: Fix two net related test failures with 64K page size", + "commit_ref": null, + "pull_url": null, + "state": "new", + "archived": false, + "hash": "3734274f90b6282e0c574a9ac2c9bda37ef5d6a0", + "submitter": { + "id": 210263, + "url": "https://patchwork.test/api/1.1/people/210263/", + "name": "Yonghong Song", + "email": "yonghong.song@linux.dev" + }, + "delegate": { + "id": 121173, + "url": "https://patchwork.test/api/1.1/users/121173/", + "username": "bpf", + "first_name": "BPF", + "last_name": "", + "email": "bpf@iogearbox.net" + }, + "mbox": "https://patchwork.test/project/netdevbpf/patch/20250611171529.2034330-1-yonghong.song@linux.dev/mbox/", + "series": [ + { + "id": 970968, + "url": "https://patchwork.test/api/1.1/series/970968/", + "web_url": "https://patchwork.test/project/netdevbpf/list/?series=970968", + "date": "2025-06-11T17:15:19", + "name": "bpf: Fix a few test failures with 64K page size", + "version": 2, + "mbox": "https://patchwork.test/series/970968/mbox/" + } + ], + "comments": "https://patchwork.test/api/patches/14114774/comments/", + "check": "warning", + "checks": "https://patchwork.test/api/patches/14114774/checks/", + "tags": {} + }, + { + "id": 14114777, + "url": "https://patchwork.test/api/1.1/patches/14114777/", + "web_url": "https://patchwork.test/project/netdevbpf/patch/20250611-rcu-fix-task_cls_state-v3-1-3d30e1de753f@posteo.net/", + "project": { + "id": 399, + "url": "https://patchwork.test/api/1.1/projects/399/", + "name": "Netdev + BPF", + "link_name": "netdevbpf", + "list_id": "bpf.vger.kernel.org", + "list_email": "bpf@vger.kernel.org", + "web_url": "", + "scm_url": "", + "webscm_url": "" + }, + "msgid": "<20250611-rcu-fix-task_cls_state-v3-1-3d30e1de753f@posteo.net>", + "date": "2025-06-11T17:20:43", + "name": "[bpf-next,v3] net: Fix RCU usage in task_cls_state() for BPF programs", + "commit_ref": null, + "pull_url": null, + "state": "new", + "archived": false, + "hash": "fb8bc5714a26b9ad4011597046c855b5a4857807", + "submitter": { + "id": 211324, + "url": "https://patchwork.test/api/1.1/people/211324/", + "name": "Charalampos Mitrodimas", + "email": "charmitro@posteo.net" + }, + "delegate": { + "id": 121173, + "url": "https://patchwork.test/api/1.1/users/121173/", + "username": "bpf", + "first_name": "BPF", + "last_name": "", + "email": "bpf@iogearbox.net" + }, + "mbox": "https://patchwork.test/project/netdevbpf/patch/20250611-rcu-fix-task_cls_state-v3-1-3d30e1de753f@posteo.net/mbox/", + "series": [ + { + "id": 970970, + "url": "https://patchwork.test/api/1.1/series/970970/", + "web_url": "https://patchwork.test/project/netdevbpf/list/?series=970970", + "date": "2025-06-11T17:20:43", + "name": "[bpf-next,v3] net: Fix RCU usage in task_cls_state() for BPF programs", + "version": 3, + "mbox": "https://patchwork.test/series/970970/mbox/" + } + ], + "comments": "https://patchwork.test/api/patches/14114777/comments/", + "check": "warning", + "checks": "https://patchwork.test/api/patches/14114777/checks/", + "tags": {} + } +] diff --git a/tests/data/test_github_sync.test_sync_patches_pr_summary_success/responses.json b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/responses.json new file mode 100644 index 0000000..f01e440 --- /dev/null +++ b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/responses.json @@ -0,0 +1,15 @@ +{ + "https://patchwork.test/api/1.1/patches/14114605/": "patch-14114605.json", + "https://patchwork.test/api/1.1/patches/14114773/": "patch-14114773.json", + "https://patchwork.test/api/1.1/patches/14114774/": "patch-14114774.json", + "https://patchwork.test/api/1.1/patches/14114775/": "patch-14114775.json", + "https://patchwork.test/api/1.1/patches/14114777/": "patch-14114777.json", + "https://patchwork.test/series/970926/mbox/": "series-970926.mbox", + "https://patchwork.test/api/1.1/series/970926/": "series-970926.json", + "https://patchwork.test/api/1.1/series/970968/": "series-970968.json", + "https://patchwork.test/api/1.1/series/970970/": "series-970970.json", + "https://patchwork.test/api/1.1/series/?q=bpf%253A+clear+user+buf+when+bpf_d_path+failed": ["series-970926.json"], + "https://patchwork.test/api/1.1/series/?q=bpf%253A+Fix+a+few+test+failures+with+64K+page+size": ["series-970968.json"], + "https://patchwork.test/api/1.1/series/?q=net%253A+Fix+RCU+usage+in+task_cls_state%2528%2529+for+BPF+programs": ["series-970970.json"], + "https://patchwork.test/api/1.1/patches/?archived=False&delegate=121173&project=399&since=2025-06-11T00:00:00&state=1&state=13&state=15&state=2&state=5&state=7": "relevant-subjects-20250610.json" +} diff --git a/tests/data/test_github_sync.test_sync_patches_pr_summary_success/series-970926.json b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/series-970926.json new file mode 100644 index 0000000..41fec6d --- /dev/null +++ b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/series-970926.json @@ -0,0 +1,41 @@ +{ + "id": 970926, + "url": "https://patchwork.test/api/1.1/series/970926/", + "web_url": "https://patchwork.test/project/netdevbpf/list/?series=970926", + "project": { + "id": 399, + "url": "https://patchwork.test/api/1.1/projects/399/", + "name": "Netdev + BPF", + "link_name": "netdevbpf", + "list_id": "bpf.vger.kernel.org", + "list_email": "bpf@vger.kernel.org", + "web_url": "", + "scm_url": "", + "webscm_url": "" + }, + "name": "[bpf-next] bpf: clear user buf when bpf_d_path failed", + "date": "2025-06-11T15:48:58", + "submitter": { + "id": 216065, + "url": "https://patchwork.test/api/1.1/people/216065/", + "name": "Tao Chen", + "email": "chen.dylane@linux.dev" + }, + "version": 1, + "total": 1, + "received_total": 1, + "received_all": true, + "mbox": "https://patchwork.test/series/970926/mbox/", + "cover_letter": null, + "patches": [ + { + "id": 14114605, + "url": "https://patchwork.test/api/1.1/patches/14114605/", + "web_url": "https://patchwork.test/project/netdevbpf/patch/20250611154859.259682-1-chen.dylane@linux.dev/", + "msgid": "<20250611154859.259682-1-chen.dylane@linux.dev>", + "date": "2025-06-11T15:48:58", + "name": "[bpf-next] bpf: clear user buf when bpf_d_path failed", + "mbox": "https://patchwork.test/project/netdevbpf/patch/20250611154859.259682-1-chen.dylane@linux.dev/mbox/" + } + ] +} diff --git a/tests/data/test_github_sync.test_sync_patches_pr_summary_success/series-970926.mbox b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/series-970926.mbox new file mode 100644 index 0000000..3ac1340 --- /dev/null +++ b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/series-970926.mbox @@ -0,0 +1,108 @@ +From patchwork Wed Jun 11 15:48:58 2025 +Content-Type: text/plain; charset="utf-8" +MIME-Version: 1.0 +Content-Transfer-Encoding: 7bit +X-Patchwork-Submitter: Tao Chen +X-Patchwork-Id: 14114605 +X-Patchwork-Delegate: bpf@iogearbox.net +Received: from out-186.mta0.migadu.com (out-186.mta0.migadu.com + [91.218.175.186]) + (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) + (No client certificate requested) + by smtp.subspace.kernel.org (Postfix) with ESMTPS id 29219198E75 + for ; Wed, 11 Jun 2025 15:49:31 +0000 (UTC) +Authentication-Results: smtp.subspace.kernel.org; + arc=none smtp.client-ip=91.218.175.186 +ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; + t=1749656974; cv=none; + b=H3sJmO/4HOlIx6kUFl6H/+BRA9KPHHH4Q7GjlSA/LngQ6EFecK1QUciBapIR6C34s0H1sz1+glg3v1exuzPTkszlKJv44cGH+VioXoRre8Y0iWC1KVwdc7RHvgffJ0XPGihrNjrcuJjt4YmUCnouwVszIm4By1xzu3Sb6+nLec8= +ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; + s=arc-20240116; t=1749656974; c=relaxed/simple; + bh=Vsu5Xaf2CfmWYXrEWUU8kTg6xy3/CnahfubB8AomyEw=; + h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; + b=dncJRD9nOpjZrsdcvYkxd2CfccDyNQ8uHadiFb/G4K5K4GAr1MRjBv/suIeI85s0iKBmv5NZ3r2PFI1g9Yus7+jBZ5z/wo42zqDVLhXSK87Dx3X+clSbiW9VqQ7wzQM1/2xFRgNIlZ12hswHopIjCQCr+w52ofYIXiH5Ug7o85Q= +ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; + dmarc=pass (p=none dis=none) header.from=linux.dev; + spf=pass smtp.mailfrom=linux.dev; + dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev + header.b=BLMetV01; arc=none smtp.client-ip=91.218.175.186 +Authentication-Results: smtp.subspace.kernel.org; + dmarc=pass (p=none dis=none) header.from=linux.dev +Authentication-Results: smtp.subspace.kernel.org; + spf=pass smtp.mailfrom=linux.dev +Authentication-Results: smtp.subspace.kernel.org; + dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev + header.b="BLMetV01" +X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and + include these headers. +DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; + t=1749656960; + h=from:from:reply-to:subject:subject:date:date:message-id:message-id: + to:to:cc:cc:mime-version:mime-version: + content-transfer-encoding:content-transfer-encoding; + bh=NkpbyMsiJRwWnx6iOR+RLlbhyzNlbJ3e38I3A+4NmfI=; + b=BLMetV01lS4FXWjpoxALr+a7Mi0irlvKqYcAZBywjBIwgNGKzGMwf6SP0SwobrqhyTbR8H + NQ/nTgeRdr9+LbZ4t/A+vxRUTO28kF4R6uvFYTrAwmTj5i/qgFhOAX9bHiICSohUcwmfK3 + WvRPHYKGvp0Puq6S/5gBm2Q5AFHG7m4= +From: Tao Chen +To: kpsingh@kernel.org, + mattbobrowski@google.com, + ast@kernel.org, + daniel@iogearbox.net, + andrii@kernel.org, + martin.lau@linux.dev, + eddyz87@gmail.com, + song@kernel.org, + yonghong.song@linux.dev, + john.fastabend@gmail.com, + sdf@fomichev.me, + haoluo@google.com, + jolsa@kernel.org, + rostedt@goodmis.org, + mhiramat@kernel.org, + mathieu.desnoyers@efficios.com +Cc: bpf@vger.kernel.org, + linux-kernel@vger.kernel.org, + linux-trace-kernel@vger.kernel.org, + Tao Chen +Subject: [PATCH bpf-next] bpf: clear user buf when bpf_d_path failed +Date: Wed, 11 Jun 2025 23:48:58 +0800 +Message-ID: <20250611154859.259682-1-chen.dylane@linux.dev> +Precedence: bulk +X-Mailing-List: bpf@vger.kernel.org +List-Id: +List-Subscribe: +List-Unsubscribe: +MIME-Version: 1.0 +X-Migadu-Flow: FLOW_OUT +X-Patchwork-Delegate: bpf@iogearbox.net + +The bpf_d_path() function may fail. If it does, +clear the user buf, like bpf_probe_read etc. + +Signed-off-by: Tao Chen +Acked-by: Song Liu +--- + kernel/trace/bpf_trace.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c +index 0998cbbb963..bb1003cb271 100644 +--- a/kernel/trace/bpf_trace.c ++++ b/kernel/trace/bpf_trace.c +@@ -916,11 +916,14 @@ BPF_CALL_3(bpf_d_path, struct path *, path, char *, buf, u32, sz) + * potentially broken verifier. + */ + len = copy_from_kernel_nofault(©, path, sizeof(*path)); +- if (len < 0) ++ if (len < 0) { ++ memset(buf, 0, sz); + return len; ++ } + + p = d_path(©, buf, sz); + if (IS_ERR(p)) { ++ memset(buf, 0, sz); + len = PTR_ERR(p); + } else { + len = buf + sz - p; diff --git a/tests/data/test_github_sync.test_sync_patches_pr_summary_success/series-970968.json b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/series-970968.json new file mode 100644 index 0000000..6cc826c --- /dev/null +++ b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/series-970968.json @@ -0,0 +1,67 @@ +{ + "id": 970968, + "url": "https://patchwork.test/api/1.1/series/970968/", + "web_url": "https://patchwork.test/project/netdevbpf/list/?series=970968", + "project": { + "id": 399, + "url": "https://patchwork.test/api/1.1/projects/399/", + "name": "Netdev + BPF", + "link_name": "netdevbpf", + "list_id": "bpf.vger.kernel.org", + "list_email": "bpf@vger.kernel.org", + "web_url": "", + "scm_url": "", + "webscm_url": "" + }, + "name": "bpf: Fix a few test failures with 64K page size", + "date": "2025-06-11T17:15:19", + "submitter": { + "id": 210263, + "url": "https://patchwork.test/api/1.1/people/210263/", + "name": "Yonghong Song", + "email": "yonghong.song@linux.dev" + }, + "version": 2, + "total": 3, + "received_total": 3, + "received_all": true, + "mbox": "https://patchwork.test/series/970968/mbox/", + "cover_letter": { + "id": 14064851, + "url": "https://patchwork.test/api/1.1/covers/14064851/", + "web_url": "https://patchwork.test/project/netdevbpf/cover/20250611171519.2033193-1-yonghong.song@linux.dev/", + "msgid": "<20250611171519.2033193-1-yonghong.song@linux.dev>", + "date": "2025-06-11T17:15:19", + "name": "[bpf-next,v2,0/3] bpf: Fix a few test failures with 64K page size", + "mbox": "https://patchwork.test/project/netdevbpf/cover/20250611171519.2033193-1-yonghong.song@linux.dev/mbox/" + }, + "patches": [ + { + "id": 14114773, + "url": "https://patchwork.test/api/1.1/patches/14114773/", + "web_url": "https://patchwork.test/project/netdevbpf/patch/20250611171524.2033657-1-yonghong.song@linux.dev/", + "msgid": "<20250611171524.2033657-1-yonghong.song@linux.dev>", + "date": "2025-06-11T17:15:24", + "name": "[bpf-next,v2,1/3] bpf: Fix an issue in bpf_prog_test_run_xdp when page size greater than 4K", + "mbox": "https://patchwork.test/project/netdevbpf/patch/20250611171524.2033657-1-yonghong.song@linux.dev/mbox/" + }, + { + "id": 14114774, + "url": "https://patchwork.test/api/1.1/patches/14114774/", + "web_url": "https://patchwork.test/project/netdevbpf/patch/20250611171529.2034330-1-yonghong.song@linux.dev/", + "msgid": "<20250611171529.2034330-1-yonghong.song@linux.dev>", + "date": "2025-06-11T17:15:29", + "name": "[bpf-next,v2,2/3] selftests/bpf: Fix two net related test failures with 64K page size", + "mbox": "https://patchwork.test/project/netdevbpf/patch/20250611171529.2034330-1-yonghong.song@linux.dev/mbox/" + }, + { + "id": 14114775, + "url": "https://patchwork.test/api/1.1/patches/14114775/", + "web_url": "https://patchwork.test/project/netdevbpf/patch/20250611171535.2034440-1-yonghong.song@linux.dev/", + "msgid": "<20250611171535.2034440-1-yonghong.song@linux.dev>", + "date": "2025-06-11T17:15:34", + "name": "[bpf-next,v2,3/3] selftests/bpf: Fix xdp_do_redirect failure with 64KB page size", + "mbox": "https://patchwork.test/project/netdevbpf/patch/20250611171535.2034440-1-yonghong.song@linux.dev/mbox/" + } + ] +} diff --git a/tests/data/test_github_sync.test_sync_patches_pr_summary_success/series-970970.json b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/series-970970.json new file mode 100644 index 0000000..007f923 --- /dev/null +++ b/tests/data/test_github_sync.test_sync_patches_pr_summary_success/series-970970.json @@ -0,0 +1,41 @@ +{ + "id": 970970, + "url": "https://patchwork.test/api/1.1/series/970970/", + "web_url": "https://patchwork.test/project/netdevbpf/list/?series=970970", + "project": { + "id": 399, + "url": "https://patchwork.test/api/1.1/projects/399/", + "name": "Netdev + BPF", + "link_name": "netdevbpf", + "list_id": "bpf.vger.kernel.org", + "list_email": "bpf@vger.kernel.org", + "web_url": "", + "scm_url": "", + "webscm_url": "" + }, + "name": "[bpf-next,v3] net: Fix RCU usage in task_cls_state() for BPF programs", + "date": "2025-06-11T17:20:43", + "submitter": { + "id": 211324, + "url": "https://patchwork.test/api/1.1/people/211324/", + "name": "Charalampos Mitrodimas", + "email": "charmitro@posteo.net" + }, + "version": 3, + "total": 1, + "received_total": 1, + "received_all": true, + "mbox": "https://patchwork.test/series/970970/mbox/", + "cover_letter": null, + "patches": [ + { + "id": 14114777, + "url": "https://patchwork.test/api/1.1/patches/14114777/", + "web_url": "https://patchwork.test/project/netdevbpf/patch/20250611-rcu-fix-task_cls_state-v3-1-3d30e1de753f@posteo.net/", + "msgid": "<20250611-rcu-fix-task_cls_state-v3-1-3d30e1de753f@posteo.net>", + "date": "2025-06-11T17:20:43", + "name": "[bpf-next,v3] net: Fix RCU usage in task_cls_state() for BPF programs", + "mbox": "https://patchwork.test/project/netdevbpf/patch/20250611-rcu-fix-task_cls_state-v3-1-3d30e1de753f@posteo.net/mbox/" + } + ] +} diff --git a/tests/test_branch_worker.py b/tests/test_branch_worker.py index 4465096..1ba1263 100644 --- a/tests/test_branch_worker.py +++ b/tests/test_branch_worker.py @@ -34,12 +34,15 @@ email_in_submitter_allowlist, EmailBodyContext, furnish_ci_email_body, - has_same_base_different_remote, - HEAD_BASE_SEPARATOR, + same_series_different_target, temporary_patch_file, UPSTREAM_REMOTE_NAME, ) -from kernel_patches_daemon.config import EmailConfig +from kernel_patches_daemon.config import ( + EmailConfig, + SERIES_TARGET_SEPARATOR, + SERIES_ID_SEPARATOR, +) from kernel_patches_daemon.github_logs import DefaultGithubLogExtractor from kernel_patches_daemon.patchwork import Series, Subject from kernel_patches_daemon.status import Status @@ -486,15 +489,17 @@ class TestCase: TestCase( name="A branch fetch pattern: expired should be deleted, not expired should not be deleted.", branches=[ - "test1" + HEAD_BASE_SEPARATOR + self._bw.repo_branch, - "test2" + HEAD_BASE_SEPARATOR + self._bw.repo_branch, + f"series{SERIES_ID_SEPARATOR}111111{SERIES_TARGET_SEPARATOR}{self._bw.repo_branch}", + f"series{SERIES_ID_SEPARATOR}222222{SERIES_TARGET_SEPARATOR}{self._bw.repo_branch}", ], fcp_called_branches=[ - "test1" + HEAD_BASE_SEPARATOR + self._bw.repo_branch, - "test2" + HEAD_BASE_SEPARATOR + self._bw.repo_branch, + f"series{SERIES_ID_SEPARATOR}111111{SERIES_TARGET_SEPARATOR}{self._bw.repo_branch}", + f"series{SERIES_ID_SEPARATOR}222222{SERIES_TARGET_SEPARATOR}{self._bw.repo_branch}", ], fcp_return_prs=[PR(updated_at=expired_time), PR()], - deleted_branches=["test1" + HEAD_BASE_SEPARATOR + self._bw.repo_branch], + deleted_branches=[ + f"series{SERIES_ID_SEPARATOR}111111{SERIES_TARGET_SEPARATOR}{self._bw.repo_branch}" + ], # filter_closed_prs for both "test1=>repo_branch", "test2=>repo_branch" # only delete "test1=>repo_branch" ), @@ -869,21 +874,23 @@ def test_create_color_labels(self) -> None: repo_mock.create_label.assert_not_called() repo_label_mock.edit.assert_called_once_with(name="label", color="00000") - def test_has_same_base_different_remote(self) -> None: - with self.subTest("same_base_different_remote"): + def test_same_series_different_target(self) -> None: + with self.subTest("same_series_different_target"): self.assertTrue( - has_same_base_different_remote("base=>remote", "base=>other_remote") + same_series_different_target( + "series/1=>target", "series/1=>other_target" + ) ) - with self.subTest("different_base_same_remote"): + with self.subTest("different_series_same_target"): self.assertFalse( - has_same_base_different_remote("base=>remote", "other_base=>remote") + same_series_different_target("series/1=>target", "series/2=>target") ) - with self.subTest("different_base_different_remote"): + with self.subTest("different_series_different_target"): self.assertFalse( - has_same_base_different_remote( - "base=>remote", "other_base=>other_remote" + same_series_different_target( + "series/1=>target", "series/2=>other_target" ) ) diff --git a/tests/test_github_sync.py b/tests/test_github_sync.py index 3690dc2..e56dce6 100644 --- a/tests/test_github_sync.py +++ b/tests/test_github_sync.py @@ -12,11 +12,15 @@ from typing import Any, Dict, Optional from unittest.mock import AsyncMock, MagicMock, patch +from aioresponses import aioresponses + from kernel_patches_daemon.branch_worker import NewPRWithNoChangeException -from kernel_patches_daemon.config import KPDConfig +from kernel_patches_daemon.config import KPDConfig, SERIES_TARGET_SEPARATOR from kernel_patches_daemon.github_sync import GithubSync +from tests.common.patchwork_mock import init_pw_responses, load_test_data, PatchworkMock TEST_BRANCH = "test-branch" +TEST_BPF_NEXT_BRANCH = "test-bpf-next" TEST_CONFIG: Dict[str, Any] = { "version": 3, "patchwork": { @@ -32,9 +36,20 @@ "upstream": "https://127.0.0.2:0/upstream_org/upstream_repo", "ci_repo": "ci-repo", "ci_branch": "test_ci_branch", - } + }, + TEST_BPF_NEXT_BRANCH: { + "repo": "bpf-next-repo", + "github_oauth_token": "bpf-next-oauth-token", + "upstream": "https://127.0.0.3:0/kernel-patches/bpf-next", + "ci_repo": "bpf-next-ci-repo", + "ci_branch": "bpf-next-ci-branch", + }, + }, + "tag_to_branch_mapping": { + "bpf-next": [TEST_BPF_NEXT_BRANCH], + "multibranch-tag": [TEST_BRANCH, TEST_BPF_NEXT_BRANCH], + "__DEFAULT__": [TEST_BRANCH], }, - "tag_to_branch_mapping": {}, "base_directory": "/tmp", } @@ -55,7 +70,7 @@ def __init__( super().__init__(*args, **presets) -class TestGihubSync(unittest.IsolatedAsyncioTestCase): +class TestGithubSync(unittest.IsolatedAsyncioTestCase): def setUp(self) -> None: patcher = patch("kernel_patches_daemon.github_connector.Github") self._gh_mock = patcher.start() @@ -103,7 +118,7 @@ class TestCase: gh.workers[TEST_BRANCH].ci_repo_dir.startswith(case.prefix), ) - def test_close_existing_prs_with_same_base(self) -> None: + def test_close_existing_prs_for_series(self) -> None: matching_pr_mock = MagicMock() matching_pr_mock.title = "matching" matching_pr_mock.head.ref = "test_branch=>remote_branch" @@ -122,7 +137,7 @@ def test_close_existing_prs_with_same_base(self) -> None: input_pr_mock.head.ref = "test_branch=>other_remote_branch" workers = [copy.copy(branch_worker_mock) for _ in range(2)] - self._gh.close_existing_prs_with_same_base(workers, input_pr_mock) + self._gh.close_existing_prs_for_series(workers, input_pr_mock) for worker in workers: self.assertEqual(len(worker.prs), 1) self.assertTrue("irrelevant" in worker.prs) @@ -163,3 +178,172 @@ async def test_checkout_and_patch_safe(self) -> None: branch_worker_mock, pr_branch_name, series ) ) + + def _setup_sync_relevant_subject_mocks(self): + """Helper method to set up common mocks for sync_relevant_subject tests.""" + series_mock = MagicMock() + series_mock.id = 12345 + series_mock.all_tags = AsyncMock(return_value=["tag"]) + subject_mock = MagicMock() + subject_mock.subject = "Test subject" + subject_mock.latest_series = AsyncMock(return_value=series_mock) + + return subject_mock, series_mock + + async def test_sync_relevant_subject_no_mapped_branches(self) -> None: + subject_mock, series_mock = self._setup_sync_relevant_subject_mocks() + self._gh.get_mapped_branches = AsyncMock(return_value=[]) + self._gh.checkout_and_patch_safe = AsyncMock() + + await self._gh.sync_relevant_subject(subject_mock) + + self._gh.get_mapped_branches.assert_called_once_with(series_mock) + self._gh.checkout_and_patch_safe.assert_not_called() + + async def test_sync_relevant_subject_success_first_branch(self) -> None: + series_prefix = "series/987654" + series_branch_name = f"{series_prefix}{SERIES_TARGET_SEPARATOR}{TEST_BRANCH}" + + subject_mock, series_mock = self._setup_sync_relevant_subject_mocks() + series_mock.all_tags = AsyncMock(return_value=["multibranch-tag"]) + subject_mock.branch = AsyncMock(return_value=series_prefix) + + pr_mock = MagicMock() + pr_mock.head.ref = series_branch_name + + self._gh.checkout_and_patch_safe = AsyncMock(return_value=pr_mock) + self._gh.close_existing_prs_for_series = MagicMock() + + worker_mock = self._gh.workers[TEST_BRANCH] + worker_mock.sync_checks = AsyncMock() + worker_mock.try_apply_mailbox_series = AsyncMock( + return_value=(True, None, None) + ) + + await self._gh.sync_relevant_subject(subject_mock) + + worker_mock.try_apply_mailbox_series.assert_called_once_with( + series_branch_name, series_mock + ) + self._gh.checkout_and_patch_safe.assert_called_once_with( + worker_mock, series_branch_name, series_mock + ) + worker_mock.sync_checks.assert_called_once_with(pr_mock, series_mock) + self._gh.close_existing_prs_for_series.assert_called_once_with( + list(self._gh.workers.values()), pr_mock + ) + + async def test_sync_relevant_subject_success_second_branch(self) -> None: + """Test sync_relevant_subject when series fails on first branch but succeeds on second.""" + series_prefix = "series/333333" + bad_branch_name = f"{series_prefix}{SERIES_TARGET_SEPARATOR}{TEST_BRANCH}" + good_branch_name = ( + f"{series_prefix}{SERIES_TARGET_SEPARATOR}{TEST_BPF_NEXT_BRANCH}" + ) + + subject_mock, series_mock = self._setup_sync_relevant_subject_mocks() + series_mock.all_tags = AsyncMock(return_value=["multibranch-tag"]) + + pr_mock = MagicMock() + pr_mock.head.ref = good_branch_name + + self._gh.checkout_and_patch_safe = AsyncMock(return_value=pr_mock) + self._gh.close_existing_prs_for_series = MagicMock() + + bad_worker_mock = self._gh.workers[TEST_BRANCH] + bad_worker_mock.sync_checks = AsyncMock() + bad_worker_mock.subject_to_branch = AsyncMock(return_value=bad_branch_name) + bad_worker_mock.try_apply_mailbox_series = AsyncMock( + return_value=(False, None, None) + ) + + good_worker_mock = self._gh.workers[TEST_BPF_NEXT_BRANCH] + good_worker_mock.sync_checks = AsyncMock() + good_worker_mock.subject_to_branch = AsyncMock(return_value=good_branch_name) + good_worker_mock.try_apply_mailbox_series = AsyncMock( + return_value=(True, None, None) + ) + + await self._gh.sync_relevant_subject(subject_mock) + + bad_worker_mock.try_apply_mailbox_series.assert_called_once_with( + bad_branch_name, series_mock + ) + good_worker_mock.try_apply_mailbox_series.assert_called_once_with( + good_branch_name, series_mock + ) + self._gh.checkout_and_patch_safe.assert_called_once_with( + good_worker_mock, good_branch_name, series_mock + ) + good_worker_mock.sync_checks.assert_called_once_with(pr_mock, series_mock) + self._gh.close_existing_prs_for_series.assert_called_once_with( + list(self._gh.workers.values()), pr_mock + ) + + @aioresponses() + async def test_sync_patches_pr_summary_success(self, m: aioresponses) -> None: + """ + This is a kind of an integration test, attempting to cover most of the + github_sync.sync_patches() happy-path code. + For patchwork mocking, it uses real response examples stored at tests/data/ + """ + + test_data = load_test_data( + "tests/data/test_github_sync.test_sync_patches_pr_summary_success" + ) + init_pw_responses(m, test_data) + + # Set up mocks and test data + patchwork = PatchworkMock( + server="patchwork.test", + api_version="1.1", + search_patterns=[{"archived": False, "project": 399, "delegate": 121173}], + auth_token="mocktoken", + ) + patchwork.since = "2025-06-11T00:00:00" + self._gh.pw = patchwork + + worker = self._gh.workers[TEST_BRANCH] + worker.repo.get_branches.return_value = [MagicMock(name=TEST_BRANCH)] + + worker = self._gh.workers[TEST_BPF_NEXT_BRANCH] + worker.repo.get_branches.return_value = [MagicMock(name=TEST_BPF_NEXT_BRANCH)] + worker.repo.create_pull.return_value = MagicMock( + html_url="https://github.com/org/repo/pull/98765" + ) + + m.post("https://patchwork.test/api/1.1/patches/14114605/checks/") + + # Execute the function under test + await self._gh.sync_patches() + + # Verify expected patches and series fetched from patchwork + get_requests = [key for key in m.requests.keys() if key[0] == "GET"] + touched_urls = set() + for req in get_requests: + touched_urls.add(str(req[1])) + self.assertIn("https://patchwork.test/api/1.1/series/970926/", touched_urls) + self.assertIn("https://patchwork.test/api/1.1/series/970968/", touched_urls) + self.assertIn("https://patchwork.test/api/1.1/series/970970/", touched_urls) + self.assertIn("https://patchwork.test/api/1.1/patches/14114605/", touched_urls) + self.assertIn("https://patchwork.test/api/1.1/patches/14114773/", touched_urls) + self.assertIn("https://patchwork.test/api/1.1/patches/14114774/", touched_urls) + self.assertIn("https://patchwork.test/api/1.1/patches/14114775/", touched_urls) + self.assertIn("https://patchwork.test/api/1.1/patches/14114777/", touched_urls) + + # Verify that a single POST request was made to patchwork + # Updating state of a patch 14114605 + post_requests = [key for key in m.requests.keys() if key[0] == "POST"] + self.assertEqual(1, len(post_requests)) + post_calls = m.requests[post_requests[0]] + url = str(post_requests[0][1]) + self.assertEqual("https://patchwork.test/api/1.1/patches/14114605/checks/", url) + self.assertEqual(1, len(post_calls)) + post_data = post_calls[0].kwargs["data"] + expected_post_data = { + "target_url": "https://github.com/org/repo/pull/98765", + "context": "vmtest-test-bpf-next-PR", + "description": "PR summary", + "state": "success", + } + self.assertDictEqual(expected_post_data, post_data) diff --git a/tests/test_patchwork.py b/tests/test_patchwork.py index 4967aab..4480142 100644 --- a/tests/test_patchwork.py +++ b/tests/test_patchwork.py @@ -636,11 +636,13 @@ async def test_relevant_series(self, m: aioresponses) -> None: init_pw_responses(m, DEFAULT_TEST_RESPONSES) s = Subject("foo", self._pw) + # There is 2 relevant series - self.assertEqual(len(await s.relevant_series), 4) + relevant_series = await s.relevant_series() + self.assertEqual(len(relevant_series), 4) # Series are ordered from oldest to newest - series = (await s.relevant_series)[0] + series = relevant_series[0] self.assertEqual(series.id, FOO_SERIES_FIRST) # It has only 1 diff, diff 11 self.assertEqual(len(await series.get_patches()), 1) @@ -655,7 +657,7 @@ async def test_latest_series(self, m: aioresponses) -> None: init_pw_responses(m, DEFAULT_TEST_RESPONSES) s = Subject("foo", self._pw) - latest_series = none_throws(await s.latest_series) + latest_series = none_throws(await s.latest_series()) # It is Series with ID FOO_SERIES_LAST self.assertEqual(latest_series.id, FOO_SERIES_LAST) # and has 3 diffs @@ -670,6 +672,6 @@ async def test_branch_name(self, m: aioresponses) -> None: init_pw_responses(m, DEFAULT_TEST_RESPONSES) s = Subject("foo", self._pw) - branch = await s.branch + branch = await s.branch() # It is Series with ID 4 self.assertEqual(branch, f"series/{FOO_SERIES_FIRST}")