From 55e3b092194f8279bdcd7d330bf89ff69b796990 Mon Sep 17 00:00:00 2001 From: wang lian Date: Wed, 10 Dec 2025 16:39:19 +0800 Subject: [PATCH 1/7] mm/khugepaged: fix comment for default scan sleep duration mainline inclusion from mainline-v6.19-rc1 commit a059ad48b453ad9ebdefaba6248229e83e5ad4d9 category: cleanup bugzilla: https://gitee.com/openeuler/kernel/issues/IDC567 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a059ad48b453ad9ebdefaba6248229e83e5ad4d9 -------------------------------- default scan period is 30 seconds. The actual default value in the code is 10000ms (10 seconds). This patch corrects the comment to match the code, preventing potential confusion. The incorrect comment has existed since the feature was first introduced. While at it, replace the magic value 512 by HPAGE_PMD_NR and use 'ptes'. Link: https://lkml.kernel.org/r/20251015092957.37432-1-lianux.mm@gmail.com Signed-off-by: wang lian Suggested-by: David Hildenbrand Reviewed-by: Dev Jain Reviewed-by: Wei Yang Reviewed-by: Lance Yang Acked-by: David Hildenbrand Reviewed-by: SeongJae Park Reviewed-by: Vishal Moola (Oracle) Acked-by: Nico Pache Cc: Andrea Arcangeli Cc: Baolin Wang Cc: Barry Song Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Rik van Riel Cc: Ryan Roberts Cc: Zi Yan Signed-off-by: Andrew Morton Signed-off-by: Wang Lian --- mm/khugepaged.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/khugepaged.c b/mm/khugepaged.c index ea4845c5f2b9..5ae36f0cd132 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -68,7 +68,7 @@ enum scan_result { static struct task_struct *khugepaged_thread __read_mostly; static DEFINE_MUTEX(khugepaged_mutex); -/* default scan 8*512 pte (or vmas) every 30 second */ +/* default scan 8*HPAGE_PMD_NR ptes (or vmas) every 10 second */ static unsigned int khugepaged_pages_to_scan __read_mostly; static unsigned int khugepaged_pages_collapsed; static unsigned int khugepaged_full_scans; -- Gitee From d0f75bb1274017fff9a0bb1d8723316d7f75a2ee Mon Sep 17 00:00:00 2001 From: Hongfu Li Date: Thu, 11 Dec 2025 16:25:30 +0800 Subject: [PATCH 2/7] khugepaged: simplify the allocation of slab caches mainline inclusion from mainline-v6.19-rc1 commit 9b94b5a2f9a95d693cfa8db6e34dcb3f1cd91204 category: cleanup bugzilla: https://gitee.com/openeuler/kernel/issues/IDC567 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9b94b5a2f9a95d693cfa8db6e34dcb3f1cd91204 -------------------------------- Use the new KMEM_CACHE() macro instead of direct kmem_cache_create to simplify the creation of SLAB caches. Link: https://lkml.kernel.org/r/20240618014517.25954-1-lihongfu@kylinos.cn Signed-off-by: Hongfu Li Acked-by: David Hildenbrand Signed-off-by: Andrew Morton Signed-off-by: Wang Lian --- mm/khugepaged.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mm/khugepaged.c b/mm/khugepaged.c index 5ae36f0cd132..0ed2840e858f 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -391,10 +391,7 @@ int hugepage_madvise(struct vm_area_struct *vma, int __init khugepaged_init(void) { - mm_slot_cache = kmem_cache_create("khugepaged_mm_slot", - sizeof(struct khugepaged_mm_slot), - __alignof__(struct khugepaged_mm_slot), - 0, NULL); + mm_slot_cache = KMEM_CACHE(khugepaged_mm_slot, 0); if (!mm_slot_cache) return -ENOMEM; -- Gitee From d1feaeea3b9e9e25f418dcd890749d989fc1d5d6 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Thu, 11 Dec 2025 14:56:46 +0800 Subject: [PATCH 3/7] mm/khugepaged: use list_xxx() helper to improve readability mainline inclusion from mainline-v6.19-rc1 commit 3615e106e0f7099af5ac8a2d4338b34b7a2dbae1 category: cleanup bugzilla: https://gitee.com/openeuler/kernel/issues/IDC567 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=3615e106e0f7099af5ac8a2d4338b34b7a2dbae1 -------------------------------- In general, khugepaged_scan_mm_slot() iterates khugepaged_scan.mm_head list to get a mm_struct for collapse memory. Use list_xxx() helper would be more obvious to the list iteration operation. No functional change. Link: https://lkml.kernel.org/r/20250822025732.9025-1-richard.weiyang@gmail.com Signed-off-by: Wei Yang Reviewed-by: Lorenzo Stoakes Acked-by: SeongJae Park Reviewed-by: Zi Yan Acked-by: David Hildenbrand Reviewed-by: Baolin Wang Reviewed-by: Dev Jain Cc: Barry Song Cc: Mariano Pache Cc: Ryan Roberts Cc: Wei Yang Signed-off-by: Andrew Morton Signed-off-by: Wang Lian --- mm/khugepaged.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mm/khugepaged.c b/mm/khugepaged.c index 0ed2840e858f..eb7164561031 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -2360,7 +2360,7 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages, int *result, mm_slot = khugepaged_scan.mm_slot; slot = &mm_slot->slot; } else { - slot = list_entry(khugepaged_scan.mm_head.next, + slot = list_first_entry(&khugepaged_scan.mm_head, struct mm_slot, mm_node); mm_slot = mm_slot_entry(slot, struct khugepaged_mm_slot, slot); khugepaged_scan.address = 0; @@ -2474,9 +2474,8 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages, int *result, * khugepaged runs here, khugepaged_exit will find * mm_slot not pointing to the exiting mm. */ - if (slot->mm_node.next != &khugepaged_scan.mm_head) { - slot = list_entry(slot->mm_node.next, - struct mm_slot, mm_node); + if (!list_is_last(&slot->mm_node, &khugepaged_scan.mm_head)) { + slot = list_next_entry(slot, mm_node); khugepaged_scan.mm_slot = mm_slot_entry(slot, struct khugepaged_mm_slot, slot); khugepaged_scan.address = 0; -- Gitee From 7f891f31b2a9919fa5a6f6e7aa2d899c96b61c4d Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Thu, 11 Dec 2025 13:50:57 +0800 Subject: [PATCH 4/7] mm/ksm: get mm_slot by mm_slot_entry() when slot is !NULL mainline inclusion from mainline-v6.19-rc1 commit 08498be43ee676d8a5eefb22278266322578a3e0 category: cleanup bugzilla: https://gitee.com/openeuler/kernel/issues/IDC567 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=08498be43ee676d8a5eefb22278266322578a3e0 -------------------------------- Patch series "mm_slot: fix the usage of mm_slot_entry", v2. When using mm_slot in ksm, there is code like: slot = mm_slot_lookup(mm_slots_hash, mm); mm_slot = mm_slot_entry(slot, struct ksm_mm_slot, slot); if (mm_slot && ..) { } The mm_slot_entry() won't return a valid value if slot is NULL generally. But currently it works since slot is the first element of struct ksm_mm_slot. To reduce the ambiguity and make it robust, access mm_slot_entry() when slot is !NULL. Link: https://lkml.kernel.org/r/20250919071244.17020-1-richard.weiyang@gmail.com Link: https://lkml.kernel.org/r/20250919071244.17020-2-richard.weiyang@gmail.com Signed-off-by: Wei Yang Acked-by: David Hildenbrand Reviewed-by: Dev Jain Reviewed-by: Lance Yang Cc: Kiryl Shutsemau Cc: xu xin Signed-off-by: Andrew Morton Signed-off-by: Wang Lian --- mm/ksm.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/mm/ksm.c b/mm/ksm.c index dac2b6d5c829..9dd639c1dc2f 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -2767,15 +2767,17 @@ void __ksm_exit(struct mm_struct *mm) spin_lock(&ksm_mmlist_lock); slot = mm_slot_lookup(mm_slots_hash, mm); - mm_slot = mm_slot_entry(slot, struct ksm_mm_slot, slot); - if (mm_slot && ksm_scan.mm_slot != mm_slot) { - if (!mm_slot->rmap_list) { - hash_del(&slot->hash); - list_del(&slot->mm_node); - easy_to_free = 1; - } else { - list_move(&slot->mm_node, - &ksm_scan.mm_slot->slot.mm_node); + if (slot) { + mm_slot = mm_slot_entry(slot, struct ksm_mm_slot, slot); + if (ksm_scan.mm_slot != mm_slot) { + if (!mm_slot->rmap_list) { + hash_del(&slot->hash); + list_del(&slot->mm_node); + easy_to_free = 1; + } else { + list_move(&slot->mm_node, + &ksm_scan.mm_slot->slot.mm_node); + } } } spin_unlock(&ksm_mmlist_lock); -- Gitee From b66deee75dd37399d6aafe850bd1ac2de8c63b85 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Thu, 11 Dec 2025 15:40:58 +0800 Subject: [PATCH 5/7] mm/khugepaged: remove definition of struct khugepaged_mm_slot mainline inclusion from mainline-v6.19-rc1 commit b4c9ffb54b3204dc8b4013c6410c897cff8cdd70 category: cleanup bugzilla: https://gitee.com/openeuler/kernel/issues/IDC567 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b4c9ffb54b3204dc8b4013c6410c897cff8cdd70 -------------------------------- Current code is not correct to get struct khugepaged_mm_slot by mm_slot_entry() without checking mm_slot is !NULL. There is no problem reported since slot is the first element of struct khugepaged_mm_slot. While struct khugepaged_mm_slot is just a wrapper of struct mm_slot, there is no need to define it. Remove the definition of struct khugepaged_mm_slot, so there is not chance to miss use mm_slot_entry(). [richard.weiyang@gmail.com: fix use-after-free crash] Link: https://lkml.kernel.org/r/20250922002834.vz6ntj36e75ehkyp@master Link: https://lkml.kernel.org/r/20250919071244.17020-3-richard.weiyang@gmail.com Signed-off-by: Wei Yang Cc: Lance Yang Cc: David Hildenbrand Cc: Dev Jain Cc: Kiryl Shutsemau Cc: xu xin Signed-off-by: Andrew Morton Signed-off-by: Wang Lian --- mm/khugepaged.c | 58 ++++++++++++++++++------------------------------- 1 file changed, 21 insertions(+), 37 deletions(-) diff --git a/mm/khugepaged.c b/mm/khugepaged.c index eb7164561031..bf7489f12d3b 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -106,14 +106,6 @@ struct collapse_control { nodemask_t alloc_nmask; }; -/** - * struct khugepaged_mm_slot - khugepaged information per mm that is being scanned - * @slot: hash lookup from mm to mm_slot - */ -struct khugepaged_mm_slot { - struct mm_slot slot; -}; - /** * struct khugepaged_scan - cursor for scanning * @mm_head: the head of the mm list to scan @@ -124,7 +116,7 @@ struct khugepaged_mm_slot { */ struct khugepaged_scan { struct list_head mm_head; - struct khugepaged_mm_slot *mm_slot; + struct mm_slot *mm_slot; unsigned long address; }; @@ -391,7 +383,10 @@ int hugepage_madvise(struct vm_area_struct *vma, int __init khugepaged_init(void) { - mm_slot_cache = KMEM_CACHE(khugepaged_mm_slot, 0); + mm_slot_cache = kmem_cache_create("khugepaged_mm_slot", + sizeof(struct mm_slot), + __alignof__(struct mm_slot), + 0, NULL); if (!mm_slot_cache) return -ENOMEM; @@ -441,7 +436,6 @@ static bool hugepage_pmd_enabled(void) void __khugepaged_enter(struct mm_struct *mm) { - struct khugepaged_mm_slot *mm_slot; struct mm_slot *slot; int wakeup; @@ -450,12 +444,10 @@ void __khugepaged_enter(struct mm_struct *mm) if (unlikely(test_and_set_bit(MMF_VM_HUGEPAGE, &mm->flags))) return; - mm_slot = mm_slot_alloc(mm_slot_cache); - if (!mm_slot) + slot = mm_slot_alloc(mm_slot_cache); + if (!slot) return; - slot = &mm_slot->slot; - spin_lock(&khugepaged_mm_lock); mm_slot_insert(mm_slots_hash, mm, slot); /* @@ -484,14 +476,12 @@ void khugepaged_enter_vma(struct vm_area_struct *vma, void __khugepaged_exit(struct mm_struct *mm) { - struct khugepaged_mm_slot *mm_slot; struct mm_slot *slot; int free = 0; spin_lock(&khugepaged_mm_lock); slot = mm_slot_lookup(mm_slots_hash, mm); - mm_slot = mm_slot_entry(slot, struct khugepaged_mm_slot, slot); - if (mm_slot && khugepaged_scan.mm_slot != mm_slot) { + if (slot && khugepaged_scan.mm_slot != slot) { hash_del(&slot->hash); list_del(&slot->mm_node); free = 1; @@ -500,9 +490,9 @@ void __khugepaged_exit(struct mm_struct *mm) if (free) { clear_bit(MMF_VM_HUGEPAGE, &mm->flags); - mm_slot_free(mm_slot_cache, mm_slot); + mm_slot_free(mm_slot_cache, slot); mmdrop(mm); - } else if (mm_slot) { + } else if (slot) { /* * This is required to serialize against * hpage_collapse_test_exit() (which is guaranteed to run @@ -1428,9 +1418,8 @@ static int hpage_collapse_scan_pmd(struct mm_struct *mm, return result; } -static void collect_mm_slot(struct khugepaged_mm_slot *mm_slot) +static void collect_mm_slot(struct mm_slot *slot) { - struct mm_slot *slot = &mm_slot->slot; struct mm_struct *mm = slot->mm; lockdep_assert_held(&khugepaged_mm_lock); @@ -1447,7 +1436,7 @@ static void collect_mm_slot(struct khugepaged_mm_slot *mm_slot) */ /* khugepaged_mm_lock actually not necessary for the below */ - mm_slot_free(mm_slot_cache, mm_slot); + mm_slot_free(mm_slot_cache, slot); mmdrop(mm); } } @@ -2346,7 +2335,6 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages, int *result, __acquires(&khugepaged_mm_lock) { struct vma_iterator vmi; - struct khugepaged_mm_slot *mm_slot; struct mm_slot *slot; struct mm_struct *mm; struct vm_area_struct *vma; @@ -2357,14 +2345,12 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages, int *result, *result = SCAN_FAIL; if (khugepaged_scan.mm_slot) { - mm_slot = khugepaged_scan.mm_slot; - slot = &mm_slot->slot; + slot = khugepaged_scan.mm_slot; } else { slot = list_first_entry(&khugepaged_scan.mm_head, struct mm_slot, mm_node); - mm_slot = mm_slot_entry(slot, struct khugepaged_mm_slot, slot); khugepaged_scan.address = 0; - khugepaged_scan.mm_slot = mm_slot; + khugepaged_scan.mm_slot = slot; } spin_unlock(&khugepaged_mm_lock); @@ -2463,7 +2449,7 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages, int *result, breakouterloop_mmap_lock: spin_lock(&khugepaged_mm_lock); - VM_BUG_ON(khugepaged_scan.mm_slot != mm_slot); + VM_BUG_ON(khugepaged_scan.mm_slot != slot); /* * Release the current mm_slot if this mm is about to die, or * if we scanned all vmas of this mm. @@ -2475,16 +2461,14 @@ static unsigned int khugepaged_scan_mm_slot(unsigned int pages, int *result, * mm_slot not pointing to the exiting mm. */ if (!list_is_last(&slot->mm_node, &khugepaged_scan.mm_head)) { - slot = list_next_entry(slot, mm_node); - khugepaged_scan.mm_slot = - mm_slot_entry(slot, struct khugepaged_mm_slot, slot); + khugepaged_scan.mm_slot = list_next_entry(slot, mm_node); khugepaged_scan.address = 0; } else { khugepaged_scan.mm_slot = NULL; khugepaged_full_scans++; } - collect_mm_slot(mm_slot); + collect_mm_slot(slot); } return progress; @@ -2571,7 +2555,7 @@ static void khugepaged_wait_work(void) static int khugepaged(void *none) { - struct khugepaged_mm_slot *mm_slot; + struct mm_slot *slot; set_freezable(); set_user_nice(current, MAX_NICE); @@ -2582,10 +2566,10 @@ static int khugepaged(void *none) } spin_lock(&khugepaged_mm_lock); - mm_slot = khugepaged_scan.mm_slot; + slot = khugepaged_scan.mm_slot; khugepaged_scan.mm_slot = NULL; - if (mm_slot) - collect_mm_slot(mm_slot); + if (slot) + collect_mm_slot(slot); spin_unlock(&khugepaged_mm_lock); return 0; } -- Gitee From 9fd3eb1088e6b731ca26ea9fc3c528f801517e16 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Fri, 12 Dec 2025 10:09:02 +0800 Subject: [PATCH 6/7] mm/ksm: cleanup mm_slot_entry() invocation mainline inclusion from mainline-v6.19-rc1 commit df6879a7483e2372fcd70762660c546446f99006 category: cleanup bugzilla: https://gitee.com/openeuler/kernel/issues/IDC567 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=df6879a7483e2372fcd70762660c546446f99006 -------------------------------- Patch series "mm_slot: following fixup for usage of mm_slot_entry()", v2. We got some late review commits during review of "mm_slot: fix the usage of mm_slot_entry()" in [1]. This patch (of 2): We got some late review commits during review of commit 08498be43ee6 ("mm/ksm: get mm_slot by mm_slot_entry() when slot is !NULL"). Let's reduce the indentation level and make the code easier to follow by using gotos to a new label. Link: https://lkml.kernel.org/r/20251001091900.20041-1-richard.weiyang@gmail.com Link: https://lkml.kernel.org/r/20251001091900.20041-2-richard.weiyang@gmail.com Link: https://lkml.kernel.org/r/20250927004539.19308-1-richard.weiyang@gmail.com [1] Fixes: 08498be43ee6 ("mm/ksm: get mm_slot by mm_slot_entry() when slot is !NULL") Signed-off-by: Wei Yang Reviewed-by: Dev Jain Acked-by: David Hildenbrand Acked-by: Kiryl Shutsemau Acked-by: Zi Yan Cc: Lance Yang Cc: xu xin Cc: Dan Carpenter Cc: Chengming Zhou Cc: Baolin Wang Cc: Barry Song Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Mariano Pache Cc: Raghavendra K T Cc: Ryan Roberts Cc: Kiryl Shutsemau Cc: SeongJae Park Signed-off-by: Andrew Morton Signed-off-by: Wang Lian --- mm/ksm.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/mm/ksm.c b/mm/ksm.c index 9dd639c1dc2f..eca4c3078383 100644 --- a/mm/ksm.c +++ b/mm/ksm.c @@ -2752,7 +2752,7 @@ int __ksm_enter(struct mm_struct *mm) void __ksm_exit(struct mm_struct *mm) { - struct ksm_mm_slot *mm_slot; + struct ksm_mm_slot *mm_slot = NULL; struct mm_slot *slot; int easy_to_free = 0; @@ -2767,19 +2767,20 @@ void __ksm_exit(struct mm_struct *mm) spin_lock(&ksm_mmlist_lock); slot = mm_slot_lookup(mm_slots_hash, mm); - if (slot) { - mm_slot = mm_slot_entry(slot, struct ksm_mm_slot, slot); - if (ksm_scan.mm_slot != mm_slot) { - if (!mm_slot->rmap_list) { - hash_del(&slot->hash); - list_del(&slot->mm_node); - easy_to_free = 1; - } else { - list_move(&slot->mm_node, - &ksm_scan.mm_slot->slot.mm_node); - } - } + if (!slot) + goto unlock; + mm_slot = mm_slot_entry(slot, struct ksm_mm_slot, slot); + if (ksm_scan.mm_slot == mm_slot) + goto unlock; + if (!mm_slot->rmap_list) { + hash_del(&slot->hash); + list_del(&slot->mm_node); + easy_to_free = 1; + } else { + list_move(&slot->mm_node, + &ksm_scan.mm_slot->slot.mm_node); } +unlock: spin_unlock(&ksm_mmlist_lock); if (easy_to_free) { -- Gitee From 05a38ab6b425df80ad89efc2efecad9c4ef60aa7 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Fri, 12 Dec 2025 10:24:38 +0800 Subject: [PATCH 7/7] mm/khugepaged: use KMEM_CACHE() mainline inclusion from mainline-v6.19-rc1 commit c14bdcc9f274620492aba7d920cc2641440cf1ba category: cleanup bugzilla: https://gitee.com/openeuler/kernel/issues/IDC567 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c14bdcc9f274620492aba7d920cc2641440cf1ba -------------------------------- We got some late review commits during review of commit b4c9ffb54b32 ("mm/khugepaged: remove definition of struct khugepaged_mm_slot"). No need to keep the old cache name "khugepaged_mm_slot", let's simply use KMEM_CACHE(). Link: https://lkml.kernel.org/r/20251001091900.20041-3-richard.weiyang@gmail.com Fixes: b4c9ffb54b32 ("mm/khugepaged: remove definition of struct khugepaged_mm_slot") Signed-off-by: Wei Yang Acked-by: Lance Yang Reviewed-by: Dev Jain Acked-by: David Hildenbrand Acked-by: Zi Yan Reviewed-by: Raghavendra K T Cc: Kiryl Shutsemau Cc: xu xin Cc: SeongJae Park Cc: Nico Pache Cc: Baolin Wang Cc: Barry Song Cc: Chengming Zhou Cc: Dan Carpenter Cc: Kiryl Shutsemau Cc: Liam Howlett Cc: Lorenzo Stoakes Cc: Ryan Roberts Signed-off-by: Andrew Morton Signed-off-by: Wang Lian --- mm/khugepaged.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/mm/khugepaged.c b/mm/khugepaged.c index bf7489f12d3b..1b9633f59893 100644 --- a/mm/khugepaged.c +++ b/mm/khugepaged.c @@ -383,10 +383,7 @@ int hugepage_madvise(struct vm_area_struct *vma, int __init khugepaged_init(void) { - mm_slot_cache = kmem_cache_create("khugepaged_mm_slot", - sizeof(struct mm_slot), - __alignof__(struct mm_slot), - 0, NULL); + mm_slot_cache = KMEM_CACHE(mm_slot, 0); if (!mm_slot_cache) return -ENOMEM; -- Gitee