cgroups(7)

الاسم
cgroups - مجموعات التحكم في لينكس

الوصف
مجموعات التحكم، ويُشار إليها عادةً باسم cgroups، هي ميزة في نواة لينكس تسمح بتنظيم العمليات في مجموعات هرمية يمكن حينها تقييد ومراقبة استخدامها لأنواع مختلفة من الموارد. توفَّر واجهة cgroup للنواة عبر نظام ملفات وهمي يسمى cgroupfs. نُفذ التجميع في كود cgroup الرئيس في النواة، بينما نُفذ تتبع الموارد والقيود في مجموعة من الأنظمة الفرعية لكل نوع مورد (الذاكرة، ووحدة المعالجة المركزية، وما إلى ذلك).

  المصطلحات
الـ cgroup هي مجموعة من العمليات المرتبطة بمجموعة من القيود أو المعاملات المحددة عبر نظام ملفات cgroup.

الـ subsystem (النظام الفرعي) هو مكون في النواة يعدل سلوك العمليات في cgroup. نُفذت أنظمة فرعية متنوعة، مما أتاح القيام بأشياء مثل تقييد مقدار وقت وحدة المعالجة المركزية والذاكرة المتاحة لـ cgroup، وحساب وقت وحدة المعالجة المركزية المستخدم بواسطة cgroup، وتجميد واستئناف تنفيذ العمليات في cgroup. تُعرف الأنظمة الفرعية أحيانًا أيضًا باسم resource controllers (متحكمات الموارد).

تُرتب الـ cgroups للمتحكم في hierarchy (هرمية). تُحدد هذه الهرمية عن طريق إنشاء وإزالة وإعادة تسمية الأدلة الفرعية داخل نظام ملفات cgroup. في كل مستوى من الهرمية، يمكن تعريف السمات (مثل القيود). القيود والتحكم والمحاسبة التي توفرها cgroups تسري عمومًا في جميع أنحاء الهرمية الفرعية الموجودة أسفل cgroup الذي عُرفت السمات فيه. وهكذا، على سبيل المثال، فإن القيود المفروضة على cgroup في مستوى أعلى في الهرمية لا يمكن تجاوزها من قِبل الـ cgroups المنحدرة منها.

  الإصدار 1 والإصدار 2 من Cgroups
كان الإصدار الأولي لتنفيذ cgroups في لينكس 2.6.24. وبمرور الوقت، أُضيفت متحكمات cgroup متنوعة للسماح بإدارة أنواع مختلفة من الموارد. ومع ذلك، كان تطوير هذه المتحكمات غير منسق إلى حد كبير، مما أدى إلى ظهور العديد من حالات عدم الاتساق بين المتحكمات وأصبحت إدارة هرميات cgroup معقدة نوعًا ما. يمكن العثور على وصف أطول لهذه المشكلات في ملف مصدر النواة Documentation/admin-guide/cgroup-v2.rst (أو Documentation/cgroup-v2.rst في لينكس 4.17 وما قبله).

بسبب المشكلات في التنفيذ الأولي لـ cgroups (الإصدار 1)، بدأ العمل في لينكس 3.10 على تنفيذ جديد ومتعامد لمعالجة هذه المشكلات. وُسم في البداية بأنه تجريبي، وكان مخفيًا خلف خيار الوصل -o __DEVEL__sane_behavior، وأصبح الإصدار الجديد (cgroups الإصدار 2) رسميًا في النهاية مع إصدار لينكس 4.5. توصف الاختلافات بين الإصدارين في النص أدناه. يعد الملف cgroup.sane_behavior، الموجود في cgroups v1، أثرًا متبقيًا من خيار الوصل هذا. يبلغ الملف دائمًا عن "0" ولا يُحتفظ به إلا للتوافق مع الإصدارات السابقة.

على الرغم من أن cgroups v2 مخصص ليكون بديلًا لـ cgroups v1، إلا أن النظام القديم لا يزال موجودًا (ومن غير المرجح إزالته لأسباب تتعلق بالتوافق). حاليًا، ينفذ cgroups v2 مجموعة فرعية فقط من المتحكمات المتوفرة في cgroups v1. نُفذ النظامان بحيث يمكن وصل كل من متحكمات v1 وv2 على نفس النظام. وهكذا، على سبيل المثال، من الممكن استخدام تلك المتحكمات المدعومة في الإصدار 2، مع استخدام متحكمات الإصدار 1 حيث لا يدعم الإصدار 2 تلك المتحكمات بعد. القيد الوحيد هنا هو أن المتحكم لا يمكن استخدامه في نفس الوقت في كل من هرمية cgroups v1 وهرمية cgroups v2.

إصدار CGROUPS رقم 1
في ظل cgroups v1، يمكن وصل كل متحكم مقابل نظام ملفات cgroup منفصل يوفر تنظيمه الهرمي الخاص للعمليات على النظام. من الممكن أيضًا وصل عدة (أو حتى جميع) متحكمات cgroups v1 معًا مقابل نفس نظام ملفات cgroup، مما يعني أن المتحكمات الموصولة معًا تدير نفس التنظيم الهرمي للعمليات.

لكل هرمية موصولة، تعكس شجرة الأدلة هرمية مجموعة التحكم. تُمثَّل كل مجموعة تحكم بواسطة دليل، مع تمثيل كل من مجموعات cgroups للتحكم الفرعية التابعة لها كدليل فرعي. على سبيل المثال، /user/joe/1.session تمثل مجموعة التحكم 1.session، وهي فرع من cgroup المسمى joe، وهو بدوره فرع من /user. يوجد تحت كل دليل cgroup مجموعة من الملفات التي يمكن قراءتها أو الكتابة إليها، مما يعكس حدود الموارد وبعض خصائص cgroup العامة.

  المهام (الخيوط) مقابل العمليات
في cgroups v1، يُرسم تمييز بين processes (العمليات) وtasks (المهام). في هذا المنظور، يمكن أن تتكون العملية من مهام متعددة (تُسمى أكثر شيوعًا بالخيوط، من منظور فضاء المستخدم، وتُسمى كذلك في بقية صفحة الدليل هذه). في cgroups v1، من الممكن التلاعب بشكل مستقل بعضويات cgroup للخيوط في العملية الواحدة.

تسببت قدرة cgroups v1 على تقسيم الخيوط عبر مجموعات cgroups مختلفة في حدوث مشكلات في بعض الحالات. على سبيل المثال، لم يكن لها معنى بالنسبة لمتحكم memory (الذاكرة)، بما أن جميع خيوط العملية تتشارك في مساحة عنوان واحدة. وبسبب هذه المشكلات، أُزيلت القدرة على التلاعب بشكل مستقل بعضويات cgroup للخيوط في العملية في التنفيذ الأولي لـ cgroups v2، وأُعيدت لاحقًا بشكل أكثر محدودية (انظر مناقشة "وضع الخيط" أدناه).

  وصل متحكمات v1
يتطلب استخدام cgroups نواة مبنية بخيار CONFIG_CGROUP. بالإضافة إلى ذلك، لكل من متحكمات v1 خيار ضبط مرتبط يجب تعيينه من أجل توظيف هذا المتحكم.

من أجل استخدام متحكم v1، يجب وصله مقابل نظام ملفات cgroup. المكان المعتاد لمثل هذه الوصلات هو تحت نظام ملفات tmpfs(5) موصول عند /sys/fs/cgroup. وهكذا، يمكن وصل متحكم cpu (وحدة المعالجة المركزية) على النحو التالي:

    mount -t cgroup -o cpu none /sys/fs/cgroup/cpu

من الممكن وصل عدة متحكمات معًا مقابل نفس الهرمية. على سبيل المثال، هنا وُصل متحكما cpu وcpuacct معًا مقابل هرمية واحدة:

    mount -t cgroup -o cpu,cpuacct none /sys/fs/cgroup/cpu,cpuacct

يؤدي وصل المتحكمات معًا إلى جعل العملية في نفس cgroup لجميع المتحكمات الموصولة معًا. يسمح وصل المتحكمات بشكل منفصل للعملية بأن تكون في cgroup باسم /foo1 لمتحكم واحد بينما تكون في /foo2/foo3 لمتحكم آخر.

من الممكن وصل جميع متحكمات v1 معًا مقابل نفس الهرمية:

    mount -t cgroup -o all cgroup /sys/fs/cgroup

(يمكن للمرء تحقيق نفس النتيجة عن طريق حذف -o all، بما أنه الخيار المبدئي إذا لم يُحدد أي متحكم صراحةً.)

لا يمكن وصل نفس المتحكم مقابل عدة هرميات cgroup. على سبيل المثال، لا يمكن وصل كل من متحكمي cpu وcpuacct مقابل هرمية واحدة، ووصل متحكم cpu وحده مقابل هرمية أخرى. من الممكن إنشاء عدة وصلات مع نفس المجموعة من المتحكمات الموصولة معًا تمامًا. ومع ذلك، في هذه الحالة كل ما ينتج هو نقاط وصل متعددة توفر عرضًا لنفس الهرمية.

لاحظ أنه في العديد من الأنظمة، تُوصل متحكمات v1 آليًا تحت /sys/fs/cgroup؛ وعلى وجه الخصوص، ينشئ systemd(1) مثل هذه الوصلات آليًا.

  فصل متحكمات v1
يمكن فصل نظام ملفات cgroup موصول باستخدام أمر umount(8)، كما في المثال التالي:

    umount /sys/fs/cgroup/pids

ولكن لاحظ جيدًا: لا يُلغى تثبيت نظام ملفات cgroup إلا إذا كان غير مشغول، أي إذا لم يكن به أي مجموعات cgroup فرعية. وإذا لم يكن الأمر كذلك، فإن التأثير الوحيد لأمر umount(8) هو جعل الوصل غير مرئي. وعلى هذا، لضمان إزالة التثبيت فعليًا، يجب أولًا إزالة جميع مجموعات cgroup الفرعية، وهو ما لا يمكن القيام به إلا بعد نقل جميع العمليات الأعضاء من تلك المجموعات إلى مجموعة cgroup الجذرية.

  متحكمات Cgroups الإصدار 1
يُحكم كل من متحكمات cgroups الإصدار 1 بواسطة خيار ضبط في النواة (المذكور أدناه). بالإضافة إلى ذلك، تُحكم توفر ميزة cgroups بواسطة خيار ضبط النواة CONFIG_CGROUPS.

cpu (منذ لينكس 2.6.24؛ CONFIG_CGROUP_SCHED)
    يمكن ضمان حد أدنى من "حصص وحدة المعالجة المركزية" لـ Cgroups عندما يكون النظام مشغولًا. هذا لا يقيد استخدام وحدة المعالجة لـ cgroup إذا كانت وحدات المعالجة غير مشغولة. لمزيد من المعلومات، انظر Documentation/scheduler/sched-design-CFS.rst.

    في لينكس 3.2، وُسع هذا المتحكم لتوفير التحكم في "عرض النطاق الترددي" لوحدة المعالجة المركزية. إذا ضُبطت النواة بـ CONFIG_CFS_BANDWIDTH، فإنه ضمن كل فترة جدولة (محددة عبر ملف في دليل cgroup)، من الممكن تحديد حد أقصى لوقت وحدة المعالجة المخصص لـ العمليات في cgroup. ينطبق هذا الحد الأقصى حتى لو لم يكن هناك تنافس آخر على وحدة المعالجة. يمكن العثور على مزيد من المعلومات في ملف مصدر النواة Documentation/scheduler/sched-bwc.rst.

cpuacct (منذ لينكس 2.6.24؛ CONFIG_CGROUP_CPUACCT)
    يوفر هذا محاسبة لاستخدام وحدة المعالجة المركزية من قبل مجموعات العمليات.

    يمكن العثور على مزيد من المعلومات في ملف مصدر النواة Documentation/admin-guide/cgroup-v1/cpuacct.rst.

cpuset (منذ لينكس 2.6.24؛ CONFIG_CPUSETS)
    يمكن استخدام مجموعة cgroup هذه لربط العمليات الموجودة في المجموعة بمجموعة محددة من وحدات المعالجة المركزية (CPU) وعقد NUMA.

    يمكن العثور على مزيد من المعلومات في ملف مصدر النواة Documentation/admin-guide/cgroup-v1/cpusets.rst.

memory (منذ لينكس 2.6.25؛ CONFIG_MEMCG)
    يدعم متحكم الذاكرة الإبلاغ عن وتقييد ذاكرة العمليات، وذاكرة النواة، ومساحة التبادل المستخدمة بواسطة cgroups.

    يمكن العثور على مزيد من المعلومات في ملف مصدر النواة Documentation/admin-guide/cgroup-v1/memory.rst.

devices (منذ لينكس 2.6.26؛ CONFIG_CGROUP_DEVICE)
    يدعم هذا التحكم في العمليات التي يمكنها إنشاء (mknod) الأجهزة وكذلك فتحها للقراءة أو الكتابة. يمكن تحديد السياسات كقوائم سماح وقوائم منع. تُفرض الهرمية، لذا يجب ألا تنتهك القواعد الجديدة القواعد الحالية للـ cgroups المستهدفة أو الأسلاف.

    يمكن العثور على مزيد من المعلومات في ملف مصدر النواة Documentation/admin-guide/cgroup-v1/devices.rst.

freezer (منذ لينكس 2.6.28؛ CONFIG_CGROUP_FREEZER)
    يمكن لـ cgroup الـ freezer تعليق واستعادة (استئناف) جميع العمليات في cgroup. يؤدي تجميد cgroup باسم /A أيضًا إلى تجميد فروعه، على سبيل المثال، العمليات في /A/B.

    يمكن العثور على مزيد من المعلومات في ملف مصدر النواة Documentation/admin-guide/cgroup-v1/freezer-subsystem.rst.

net_cls (منذ لينكس 2.6.29؛ CONFIG_CGROUP_NET_CLASSID)
    يضع هذا معرف فئة (classid)، محدد لـ cgroup، على حزم الشبكة المنشأة بواسطة cgroup. يمكن حينها استخدام معرفات الفئات هذه في قواعد جدار الحماية، وكذلك استخدامها لتشكيل حركة المرور باستخدام tc(8). ينطبق هذا فقط على الحزم المغادرة لـ cgroup، وليس على حركة المرور القادمة إليه.

    يمكن العثور على مزيد من المعلومات في ملف مصدر النواة Documentation/admin-guide/cgroup-v1/net_cls.rst.

blkio (منذ لينكس 2.6.33؛ CONFIG_BLK_CGROUP)
    يتحكم cgroup الـ blkio ويقيد الوصول إلى أجهزة كتلية محددة من خلال تطبيق التحكم في الإدخال والإخراج في شكل خنق وحدود قصوى ضد العقد الطرفية والعقد الوسيطة في هرمية التخزين.

    تتوفر سياستان. الأولى هي تقسيم وقت القرص بوزن نسبي منفذ مع CFQ. يسري هذا على العقد الطرفية التي تستخدم CFQ. والثانية هي سياسة خنق تحدد الحدود القصوى لمعدل الإدخال والإخراج على الجهاز.

    يمكن العثور على مزيد من المعلومات في ملف مصدر النواة Documentation/admin-guide/cgroup-v1/blkio-controller.rst.

perf_event (منذ لينكس 2.6.39؛ CONFIG_CGROUP_PERF)
    يسمح هذا المتحكم بمراقبة perf لمجموعة العمليات المجمعة في cgroup.

    يمكن العثور على مزيد من المعلومات في ملفات مصدر النواة

net_prio (منذ لينكس 3.3؛ CONFIG_CGROUP_NET_PRIO)
    يسمح هذا بتحديد الأولويات، لكل واجهة شبكة، لـ cgroups.

    يمكن العثور على مزيد من المعلومات في ملف مصدر النواة Documentation/admin-guide/cgroup-v1/net_prio.rst.

hugetlb (منذ لينكس 3.5؛ CONFIG_CGROUP_HUGETLB)
    يدعم هذا تقييد استخدام الصفحات الضخمة بواسطة cgroups.

    يمكن العثور على مزيد من المعلومات في ملف مصدر النواة Documentation/admin-guide/cgroup-v1/hugetlb.rst.

pids (منذ لينكس 4.3؛ CONFIG_CGROUP_PIDS)
    يسمح هذا المتحكم بتقييد عدد العمليات التي يمكن إنشاؤها في cgroup (والمنحدرين منه).

    يمكن العثور على مزيد من المعلومات في ملف مصدر النواة Documentation/admin-guide/cgroup-v1/pids.rst.

rdma (منذ لينكس 4.11؛ CONFIG_CGROUP_RDMA)
    يسمح متحكم RDMA بتقييد استخدام موارد RDMA/IB الخاصة لكل cgroup.

    يمكن العثور على مزيد من المعلومات في ملف مصدر النواة Documentation/admin-guide/cgroup-v1/rdma.rst.

  إنشاء cgroups ونقل العمليات
يحتوي نظام ملفات cgroup في البداية على cgroup رئيس واحد، '/'، تنتمي إليه جميع العمليات. يُنشأ cgroup جديد عن طريق إنشاء دليل في نظام ملفات cgroup:

    mkdir /sys/fs/cgroup/cpu/cg1

يؤدي هذا لإنشاء cgroup فارغ جديد.

يمكن نقل عملية إلى هذا الـ cgroup عن طريق كتابة معرفها (PID) في ملف cgroup.procs الخاص بـ cgroup:

    echo $$ > /sys/fs/cgroup/cpu/cg1/cgroup.procs

يجب كتابة معرف PID واحد فقط في كل مرة في هذا الملف.

تؤدي كتابة القيمة 0 إلى ملف cgroup.procs إلى نقل عملية الكتابة إلى الـ cgroup المقابل.

عند كتابة PID في cgroup.procs، تُنقل جميع الخيوط في العملية إلى الـ cgroup الجديد دفعة واحدة.

داخل الهرمية، يمكن أن تكون العملية عضوًا في cgroup واحد فقط. تؤدي كتابة معرف PID للعملية في ملف cgroup.procs إلى إزالتها آليًا من cgroup الذي كانت عضواً فيه سابقاً.

يمكن قراءة ملف cgroup.procs للحصول على قائمة بالعمليات الأعضاء في cgroup. قائمة معرفات PID المرجعة لا يُضمن ترتيبها. كما لا يُضمن خلوها من التكرارات. (على سبيل المثال، قد يُعاد استخدام PID أثناء القراءة من القائمة).

في cgroups v1، يمكن نقل خيط فردي إلى cgroup آخر عن طريق كتابة معرف الخيط الخاص به (أي معرف خيط النواة المرجع بواسطة clone(2) وgettid(2)) في ملف tasks في دليل cgroup. يمكن قراءة هذا الملف لاكتشاف مجموعة الخيوط الأعضاء في cgroup.

  إزالة cgroups
لإزالة cgroup، يجب أولاً ألا يحتوي على cgroups فرعية ولا يحتوي على عمليات (غير ميتة/zombie). طالما كان الأمر كذلك، يمكن ببساطة إزالة مسار الدليل المقابل. لاحظ أن الملفات الموجودة في دليل cgroup لا يمكن ولا داعي لإزالتها.

  إشعار تحرير Cgroups v1
يمكن استخدام ملفين لتحديد ما إذا كانت النواة توفر إشعارات عندما يصبح cgroup فارغًا. يُعتبر cgroup فارغًا عندما لا يحتوي على cgroups فرعية ولا عمليات أعضاء.

يمكن استخدام ملف خاص في الدليل الرئيس لكل هرمية cgroup، release_agent، لتسجيل مسار برنامج قد يُستدعى عندما يصبح cgroup في الهرمية فارغًا. يُوفَّر مسار cgroup الفارغ حديثًا (بالنسبة لنقطة وصل cgroup) كوسيط وحيد لسطر الأوامر عند استدعاء برنامج release_agent. قد يقوم برنامج release_agent بإزالة دليل cgroup، أو ربما إعادة ملئه بعملية.

القيمة المبدئية لملف release_agent فارغة، مما يعني أنه لا يُستدعى أي وكيل تحرير.

يمكن أيضًا تحديد محتوى ملف release_agent عبر خيار وصل عند وصل نظام ملفات cgroup:

    mount -o release_agent=pathname ...

يُحدد ما إذا كان برنامج release_agent سيُستدعى أم لا عندما تصبح مجموعة تحكم (cgroup) معينة فارغة بناءً على القيمة الموجودة في ملف notify_on_release في دليل مجموعة التحكم المقابل. إذا كان هذا الملف يحتوي على القيمة 0، فلن يُستدعى برنامج release_agent. وإذا احتوى على القيمة 1، فسيُستدعى برنامج release_agent. القيمة المبدئية لهذا الملف في مجموعة التحكم الرئيسة (root cgroup) هي 0. عند إنشاء مجموعة تحكم جديدة، تُورث القيمة في هذا الملف من الملف المقابل في مجموعة التحكم الأب.

  التسلسلات الهرمية المسماة في الإصدار الأول لمجموعات التحكم (cgroups v1)
في الإصدار الأول لمجموعات التحكم (cgroups v1)، يمكن وصل تسلسل هرمي لمجموعة التحكم لا يحتوي على متحكمات مرفقة:

    mount -t cgroup -o none,name=somename none /some/mount/point

يمكن وصل مثيلات متعددة من هذه التسلسلات الهرمية؛ ويجب أن يكون لكل تسلسل هرمي اسم فريد. الغرض الوحيد من هذه التسلسلات هو تتبع العمليات. (راجع نقاش إشعارات التحرير أدناه). ومثال على ذلك هو التسلسل الهرمي لمجموعة التحكم name=systemd الذي يستخدمه systemd(1) لتتبع الخدمات وجلسات المستخدم.

بدءًا من لينكس 5.0، يمكن استخدام خيار تمهيد النواة cgroup_no_v1 (الموضح أدناه) لتعطيل التسلسلات الهرمية المسماة في الإصدار الأول لمجموعات التحكم، وذلك بتحديد cgroup_no_v1=named.

الإصدار الثاني لمجموعات التحكم (CGROUPS VERSION 2)
في الإصدار الثاني لمجموعات التحكم (cgroups v2)، توجد جميع المتحكمات الموصولة في تسلسل هرمي موحد واحد. وبينما قد تُوصل متحكمات (مختلفة) في آن واحد تحت تسلسلات الإصدار الأول والثاني، فإنه لا يمكن وصل المتحكم نفسه في آن واحد تحت كل من تسلسلات الإصدار الأول والثاني.

تُلخص السلوكيات الجديدة في الإصدار الثاني لمجموعات التحكم هنا، وفي بعض الحالات تُفصّل في الفروع التالية.

•   يوفر الإصدار الثاني لمجموعات التحكم تسلسلاً هرمياً موحداً تُوصل إليه جميع المتحكمات.

•   العمليات "الداخلية" غير مسموح بها. باستثناء مجموعة التحكم الرئيسة (root cgroup)، لا يمكن للعمليات أن توجد إلا في العقد الطرفية (مجموعات التحكم التي لا تحتوي أنفسها على مجموعات تحكم تابعة). التفاصيل أكثر دقة من ذلك، وهي موضحة أدناه.

•   يجب تحديد مجموعات التحكم النشطة عبر الملفين cgroup.controllers و cgroup.subtree_control.

•   أُزيل ملف tasks. بالإضافة إلى ذلك، أُزيل ملف cgroup.clone_children الذي يستخدمه متحكم cpuset.

•   تُوفر آلية محسنة للإشعار عن مجموعات التحكم الفارغة بواسطة ملف cgroup.events.

لمزيد من التغييرات، راجع ملف Documentation/admin-guide/cgroup-v2.rst في مصدر النواة.

شهدت بعض السلوكيات الجديدة المذكورة أعلاه تعديلات لاحقة مع إضافة "وضع الخيوط" (thread mode) في لينكس 4.14 (الموضح أدناه).

  التسلسل الهرمي الموحد في الإصدار الثاني لمجموعات التحكم
في الإصدار الأول لمجموعات التحكم، كان الهدف من القدرة على وصل متحكمات مختلفة في تسلسلات هرمية مختلفة هو السماح بمرونة كبيرة لتصميم التطبيقات. ولكن من الناحية العملية، تبين أن هذه المرونة كانت أقل فائدة مما هو متوقع، وزادت التعقيد في حالات كثيرة. لذلك، في الإصدار الثاني لمجموعات التحكم، تُوصل جميع المتحكمات المتاحة في تسلسل هرمي واحد. وتُوصل المتحكمات المتاحة آلياً، مما يعني أنه ليس من الضروري (أو الممكن) تحديد المتحكمات عند وصل نظام ملفات الإصدار الثاني لمجموعات التحكم باستخدام أمر مثل التالي:

    mount -t cgroup2 none /mnt/cgroup2

يكون متحكم الإصدار الثاني متاحاً فقط إذا لم يكن قيد الاستخدام حالياً عبر وصله في تسلسل هرمي للإصدار الأول. أو بعبارة أخرى، لا يمكن استخدام المتحكم ذاته في كل من تسلسل الإصدار الأول وتسلسل الإصدار الثاني الموحد. وهذا يعني أنه قد يكون من الضروري أولاً فصل متحكم الإصدار الأول (كما هو موضح أعلاه) قبل أن يصبح ذلك المتحكم متاحاً في الإصدار الثاني. وبما أن systemd(1) يستخدم بعض متحكمات الإصدار الأول بكثافة بشكل مبدئي، فقد يكون من الأبسط في بعض الحالات تمهيد النظام مع تعطيل متحكمات مختارة من الإصدار الأول. وللقيام بذلك، حدد الخيار cgroup_no_v1=list في سطر أوامر تمهيد النواة؛ حيث list هي قائمة بأسماء المتحكمات المراد تعطيلها مفصولة بفاصلة، أو كلمة all لتعطيل جميع متحكمات الإصدار الأول. (يتم التعامل مع هذه الحالة بشكل صحيح بواسطة systemd(1)، الذي يتراجع للعمل بدون المتحكمات المحددة).

لاحظ أنه في العديد من الأنظمة الحديثة، يقوم systemd(1) آلياً بوصل نظام ملفات cgroup2 في المسار /sys/fs/cgroup/unified أثناء عملية التمهيد.

  خيارات وصل الإصدار الثاني لمجموعات التحكم
يمكن تحديد الخيارات التالية (mount -o) عند وصل نظام ملفات الإصدار الثاني لمجموعات التحكم:

nsdelegate (منذ لينكس 4.15)
    يعامل نطاقات أسماء مجموعات التحكم كحدود تفويض. للتفاصيل، انظر أدناه.

memory_localevents (منذ لينكس 5.2)
    يجب أن يعرض memory.events الإحصائيات لمجموعة التحكم نفسها فقط، وليس لأي مجموعات تحكم تابعة. كان هذا هو السلوك قبل لينكس 5.2. ومنذ لينكس 5.2، أصبح السلوك المبدئي هو تضمين إحصائيات مجموعات التحكم التابعة في memory.events، ويمكن استخدام خيار الوصل هذا للعودة إلى السلوك القديم. هذا الخيار على مستوى النظام ويمكن ضبطه عند الوصل أو تعديله عبر إعادة الوصل فقط من نطاق أسماء الوصل الأولي؛ ويتم تجاهله بصمت في نطاقات الأسماء غير الأولية.

  متحكمات الإصدار الثاني لمجموعات التحكم
المتحكمات التالية، والموثقة في ملف مصدر النواة Documentation/admin-guide/cgroup-v2.rst، مدعومة في الإصدار الثاني لمجموعات التحكم:

cpu (منذ لينكس 4.15)
    هذا هو الوريث لمتحكمي cpu و cpuacct من الإصدار الأول.

cpuset (منذ لينكس 5.0)
    هذا هو الوريث لمتحكم cpuset من الإصدار الأول.

freezer (منذ لينكس 5.2)
    هذا هو الوريث لمتحكم freezer من الإصدار الأول.

hugetlb (منذ لينكس 5.6)
    هذا هو الوريث لمتحكم hugetlb من الإصدار الأول.

io (منذ لينكس 4.5)
    هذا هو الوريث لمتحكم blkio من الإصدار الأول.

memory (منذ لينكس 4.5)
    هذا هو الوريث لمتحكم memory من الإصدار الأول.

perf_event (منذ لينكس 4.11)
    هذا هو نفس متحكم perf_event من الإصدار الأول.

pids (منذ لينكس 4.5)
    هذا هو نفس متحكم pids من الإصدار الأول.

rdma (منذ لينكس 4.11)
    هذا هو نفس متحكم rdma من الإصدار الأول.

لا يوجد مكافئ مباشر لمتحكمي net_cls و net_prio من الإصدار الأول لمجموعات التحكم. بدلاً من ذلك، أُضيفت ميزة الدعم إلى iptables(8) للسماح لمرشحات eBPF التي ترتبط بمسارات الإصدار الثاني لمجموعات التحكم باتخاذ قرارات بشأن حركة مرور الشبكة على أساس كل مجموعة تحكم.

لا يوفر متحكم الأجهزة devices في الإصدار الثاني أي ملفات واجهة؛ بدلاً من ذلك، يتم التحكم في الأجهزة عن طريق إرفاق برنامج eBPF (BPF_CGROUP_DEVICE) بمجموعة تحكم من الإصدار الثاني.

  التحكم في الشجرة الفرعية في الإصدار الثاني لمجموعات التحكم
تحتوي كل مجموعة تحكم في تسلسل الإصدار الثاني الهرمي على الملفين التاليين:

cgroup.controllers
    يعرض هذا الملف المخصص للقراءة فقط قائمة بالمتحكمات المتاحة في مجموعة التحكم هذه. وتتطابق محتويات هذا الملف مع محتويات ملف cgroup.subtree_control في مجموعة التحكم الأب.

cgroup.subtree_control
    هذه قائمة بالمتحكمات النشطة (المفعلة) في مجموعة التحكم. مجموعة المتحكمات في هذا الملف هي مجموعة جزئية من المجموعة الموجودة في ملف cgroup.controllers لمجموعة التحكم هذه. تُعدل مجموعة المتحكمات النشطة بكتابة سلاسل نصية في هذا الملف تحتوي على أسماء المتحكمات مفصولة بمسافات، وكل منها مسبوق بـ '+' (لتفعيل المتحكم) أو '-' (لتعطيل المتحكم)، كما في المثال التالي:

        echo '+pids -memory' > x/y/cgroup.subtree_control

    تؤدي محاولة تفعيل متحكم غير موجود في cgroup.controllers إلى خطأ ENOENT عند الكتابة في ملف cgroup.subtree_control.

بما أن قائمة المتحكمات في cgroup.subtree_control هي مجموعة جزئية من تلك الموجودة في cgroup.controllers، فإن المتحكم الذي عُطّل في إحدى مجموعات التحكم في التسلسل الهرمي لا يمكن أبداً إعادة تفعيله في الشجرة الفرعية تحت مجموعة التحكم تلك.

يحدد ملف cgroup.subtree_control الخاص بمجموعة التحكم مجموعة المتحكمات التي تُطبق في مجموعات التحكم التابعة. عندما يكون المتحكم (مثلاً pids) موجوداً في ملف cgroup.subtree_control لمجموعة التحكم الأب، فإن ملفات واجهة المتحكم المقابلة (مثلاً pids.max) تُنشأ آلياً في المجموعات التابعة لمجموعة التحكم تلك ويمكن استخدامها لممارسة التحكم في الموارد في مجموعات التحكم التابعة.

  قاعدة "عدم وجود عمليات داخلية" في الإصدار الثاني لمجموعات التحكم
يفرض الإصدار الثاني لمجموعات التحكم ما يسمى بقاعدة "عدم وجود عمليات داخلية". وبشكل تقريبي، تعني هذه القاعدة أنه باستثناء مجموعة التحكم الرئيسة، لا يمكن للعمليات أن توجد إلا في العقد الطرفية (مجموعات التحكم التي لا تحتوي هي نفسها على مجموعات تحكم تابعة). وهذا يتجنب الحاجة إلى تقرير كيفية تقسيم الموارد بين العمليات التي هي أعضاء في مجموعة التحكم A والعمليات في مجموعات التحكم التابعة لـ A.

على سبيل المثال، إذا كانت مجموعة التحكم /cg1/cg2 موجودة، فقد توجد العملية في /cg1/cg2، ولكن ليس في /cg1. وهذا لتجنب الغموض الذي كان موجوداً في الإصدار الأول فيما يتعلق بتفويض الموارد بين العمليات في /cg1 ومجموعاتها التابعة. النهج الموصى به في الإصدار الثاني هو إنشاء دليل فرعي يسمى leaf لأي مجموعة تحكم غير طرفية يجب أن تحتوي على عمليات، ولكن بدون مجموعات تحكم تابعة. وبالتالي، فإن العمليات التي كانت ستذهب سابقاً إلى /cg1 ستذهب الآن إلى /cg1/leaf. وهذا له ميزة جعل العلاقة صريحة بين العمليات في /cg1/leaf والمجموعات التابعة الأخرى لـ /cg1.

قاعدة "عدم وجود عمليات داخلية" هي في الواقع أكثر دقة مما ذُكر أعلاه. وبشكل أكثر دقة، القاعدة هي أن مجموعة التحكم (غير الرئيسة) لا يمكنها أن تجمع بين (1) وجود عمليات عضوة فيها، و (2) توزيع الموارد إلى مجموعات تحكم تابعة—أي أن يكون ملف cgroup.subtree_control فيها غير فارغ. وبالتالي، من الممكن لمجموعة تحكم أن تحتوي على عمليات عضوة ومجموعات تابعة في آن واحد، ولكن قبل تفعيل المتحكمات لمجموعة التحكم تلك، يجب نقل العمليات العضوة خارجها (مثلاً، ربما إلى مجموعات التحكم التابعة).

مع إضافة "وضع الخيوط" (thread mode) في لينكس 4.14 (الموضح أدناه)، خُففت قاعدة "عدم وجود عمليات داخلية" في بعض الحالات.

  ملف cgroup.events في الإصدار الثاني لمجموعات التحكم
تحتوي كل مجموعة تحكم غير رئيسة في تسلسل الإصدار الثاني الهرمي على ملف للقراءة فقط، cgroup.events، ومحتوياته هي أزواج (مفتاح-قيمة) (مفصولة بأحرف سطر جديد، مع مسافة بين المفتاح والقيمة) توفر معلومات عن حالة مجموعة التحكم:

    $ cat mygrp/cgroup.events
    populated 1
    frozen 0

قد تظهر المفاتيح التالية في هذا الملف:

populated
    قيمة هذا المفتاح هي إما 1، إذا كانت مجموعة التحكم هذه أو أي من توابعها تحتوي على عمليات عضوة، أو 0 خلاف ذلك.

frozen (منذ لينكس 5.2)
    قيمة هذا المفتاح هي 1 إذا كانت مجموعة التحكم هذه مجمدة حالياً، أو 0 إذا لم تكن كذلك.

يمكن مراقبة ملف cgroup.events لتلقي إشعار عند تغير قيمة أحد مفاتيحه. يمكن إجراء هذه المراقبة باستخدام inotify(7)، الذي يشعر بالتغييرات كأحداث IN_MODIFY، أو poll(2)، الذي يشعر بالتغييرات عبر إرجاع بتات POLLPRI و POLLERR في حقل revents.

  إشعارات التحرير في الإصدار الثاني لمجموعات التحكم
يوفر الإصدار الثاني لمجموعات التحكم آلية جديدة للحصول على إشعار عندما تصبح مجموعة التحكم فارغة. أُزيل ملفا release_agent و notify_on_release الخاصان بالإصدار الأول، واستُبدلا بمفتاح populated في ملف cgroup.events. هذا المفتاح يأخذ إما القيمة 0، مما يعني أن مجموعة التحكم (وتوابعها) لا تحتوي على عمليات عضوة (غير ميتة)، أو القيمة 1، مما يعني أن مجموعة التحكم (أو أحد توابعها) تحتوي على عمليات عضوة.

تقدم آلية إشعار التحرير في الإصدار الثاني لمجموعات التحكم المزايا التالية على آلية release_agent في الإصدار الأول:

•   تسمح بإشعارات أقل كلفة، حيث يمكن لعملية واحدة مراقبة ملفات cgroup.events متعددة (باستخدام التقنيات الموصوفة سابقاً). وبالمقابل، تتطلب آلية الإصدار الأول كلفة إنشاء عملية لكل إشعار.

•   يمكن تفويض الإشعارات لمختلف الأشجار الفرعية لمجموعات التحكم إلى عمليات مختلفة. وبالمقابل، لا تسمح آلية الإصدار الأول إلا بوكيل تحرير واحد للتسلسل الهرمي بأكمله.

  ملف cgroup.stat في الإصدار الثاني لمجموعات التحكم
تحتوي كل مجموعة تحكم في تسلسل الإصدار الثاني الهرمي على ملف cgroup.stat للقراءة فقط (قُدم لأول مرة في لينكس 4.14) يتكون من أسطر تحتوي على أزواج (مفتاح-قيمة). تظهر المفاتيح التالية حالياً في هذا الملف:

nr_descendants
    هذا هو العدد الإجمالي لمجموعات التحكم التابعة المرئية (أي الحية) تحت مجموعة التحكم هذه.

nr_dying_descendants
    هذا هو العدد الإجمالي لمجموعات التحكم التابعة المحتضرة (التي في طور الزوال) تحت مجموعة التحكم هذه. تدخل مجموعة التحكم في حالة الاحتضار بعد حذفها. وتظل في تلك الحالة لفترة غير محددة (تعتمد على حمل النظام) بينما تُحرر الموارد قبل تدمير مجموعة التحكم. لاحظ أن وجود بعض مجموعات التحكم في حالة الاحتضار أمر طبيعي، ولا يشير إلى أي مشكلة.

    لا يمكن جعل العملية عضواً في مجموعة تحكم محتضرة، ولا يمكن إعادة مجموعة تحكم محتضرة إلى الحياة.

  تحديد عدد مجموعات التحكم التابعة
تحتوي كل مجموعة تحكم في تسلسل الإصدار الثاني الهرمي على الملفات التالية، والتي يمكن استخدامها لعرض وضبط حدود لعدد مجموعات التحكم التابعة تحت مجموعة التحكم تلك:

cgroup.max.depth (منذ لينكس 4.14)
    يحدد هذا الملف حداً لعمق تعشيش مجموعات التحكم التابعة. القيمة 0 في هذا الملف تعني أنه لا يمكن إنشاء أي مجموعات تحكم تابعة. وتفشل أي محاولة لإنشاء تابع يتجاوز مستوى تعشيشه هذا الحد (يفشل mkdir(2) مع الخطأ EAGAIN).

    كتابة السلسلة النصية "max" في هذا الملف تعني عدم فرض أي حد. القيمة المبدئية في هذا الملف هي "max".

cgroup.max.descendants (منذ لينكس 4.14)
    يحدد هذا الملف حداً لعدد مجموعات التحكم التابعة الحية التي يمكن لمجموعة التحكم هذه امتلاكها. وتفشل أي محاولة لإنشاء توابع أكثر مما يسمح به الحد (يفشل mkdir(2) مع الخطأ EAGAIN).

    كتابة السلسلة النصية "max" في هذا الملف تعني عدم فرض أي حد. القيمة المبدئية في هذا الملف هي "max".

تفويض مجموعات التحكم: تفويض تسلسل هرمي لمستخدم أقل امتيازاً
في سياق مجموعات التحكم، يعني التفويض نقل إدارة شجرة فرعية ما من التسلسل الهرمي لمجموعات التحكم إلى مستخدم غير متمتع بالامتيازات. يوفر الإصدار الأول لمجموعات التحكم دعماً للتفويض بناءً على أذونات الملفات في تسلسل مجموعات التحكم ولكن بقواعد احتواء أقل صرامة من الإصدار الثاني (كما هو مذكور أدناه). يدعم الإصدار الثاني لمجموعات التحكم التفويض مع الاحتواء بتصميم صريح. يركز النقاش في هذا القسم على التفويض في الإصدار الثاني، مع الإشارة إلى بعض الاختلافات في الإصدار الأول خلال السياق.

ثمة مصطلحات مطلوبة لوصف التفويض. المُفوِّض (delegater) هو مستخدم متمتع بالامتيازات (أي root) يملك مجموعة تحكم أب. والمُفوَّض إليه (delegatee) هو مستخدم غير متمتع بالامتيازات سيُمنح الأذونات اللازمة لإدارة تسلسل هرمي فرعي تحت مجموعة التحكم الأب تلك، والمعروف باسم الشجرة الفرعية المفوضة.

لإجراء التفويض، يقوم المُفوِّض بجعل أدلة وملفات معينة قابلة للكتابة بواسطة المُفوَّض إليه، وعادةً ما يكون ذلك بتغيير ملكية الكائنات لتصبح معرف المستخدم (UID) الخاص بالمُفوَّض إليه. بافتراض أننا نريد تفويض التسلسل الهرمي الذي يبدأ من (مثلاً) /dlgt_grp وأنه لا توجد بعد أي مجموعات تحكم تابعة تحت تلك المجموعة، تُغير ملكية ما يلي إلى معرف المستخدم الخاص بالمُفوَّض إليه:

/dlgt_grp
    يعني تغيير ملكية رأس الشجرة الفرعية أن أي مجموعات تحكم جديدة تُنشأ تحت تلك الشجرة (والملفات التي تحتويها) ستكون مملوكة أيضًا للمُفوَّض إليه.

/dlgt_grp/cgroup.procs
    تغيير ملكية هذا الملف يعني أن المفوَّض إليه يمكنه نقل العمليات إلى جذر الشجرة الفرعية المفوَّضة.

/dlgt_grp/cgroup.subtree_control (cgroups v2 فقط)
    تغيير ملكية هذا الملف يعني أن المفوَّض إليه يمكنه تفعيل المتحكمات (الموجودة في /dlgt_grp/cgroup.controllers) من أجل إعادة توزيع الموارد على مستويات أدنى في الشجرة الفرعية. (كبديل لتغيير ملكية هذا الملف، قد يقوم المفوِّض بدلاً من ذلك بإضافة متحكمات مختارة إلى هذا الملف.)

/dlgt_grp/cgroup.threads (cgroups v2 فقط)
    يعد تغيير ملكية هذا الملف ضرورياً إذا وُفِّضت شجرة فرعية خيطية (انظر وصف "وضع الخيوط" أدناه). يسمح هذا للمفوَّض إليه بكتابة معرفات الخيوط إلى الملف. (يمكن أيضًا تغيير ملكية هذا الملف عند تفويض شجرة فرعية لنطاق، ولكن هذا لا يخدم أي غرض حالياً، لأنه -كما هو موضح أدناه- لا يمكن نقل خيط بين مجموعات تحكم النطاق عبر كتابة معرف الخيط الخاص به في ملف cgroup.threads.)

    في مجموعات التحكم الإصدار 1 (cgroups v1)، الملف المقابل الذي ينبغي تفويضه بدلاً من ذلك هو ملف tasks.

ينبغي على المفوِّض عدم تغيير ملكية أي من ملفات واجهة المتحكم (مثل pids.max، memory.high) في dlgt_grp. تُستخدم تلك الملفات من المستوى التالي فوق الشجرة الفرعية المفوَّضة من أجل توزيع الموارد داخل الشجرة الفرعية، ولا ينبغي أن يملك المفوَّض إليه إذناً لتغيير الموارد التي تُوزَّع داخل الشجرة الفرعية المفوَّضة.

انظر أيضًا مناقشة ملف /sys/kernel/cgroup/delegate في قسم الملاحظات (NOTES) للحصول على معلومات حول المزيد من الملفات القابلة للتفويض في cgroups v2.

بعد تنفيذ الخطوات المذكورة سابقاً، يمكن للمفوَّض إليه إنشاء مجموعات تحكم فرعية داخل الشجرة الفرعية المفوَّضة (ستكون أدلة مجموعات التحكم الفرعية والملفات التي تحتوي عليها مملوكة للمفوَّض إليه) ونقل العمليات بين مجموعات التحكم في الشجرة الفرعية. إذا كانت بعض المتحكمات موجودة في dlgt_grp/cgroup.subtree_control، أو نُقلت ملكية ذلك الملف إلى المفوَّض إليه، فيمكنه أيضًا التحكم في إعادة التوزيع اللاحقة للموارد المقابلة داخل الشجرة الفرعية المفوَّضة.

  تفويض مجموعات التحكم v2: خيار nsdelegate ونطاقات أسماء cgroup
بدءاً من لينكس 4.13، توجد طريقة ثانية لإجراء تفويض مجموعات التحكم في هرمية cgroups v2. يتم ذلك عبر وصل نظام ملفات cgroup v2 أو إعادة وصله مع خيار الوصل nsdelegate. على سبيل المثال، إذا وُصل نظام ملفات cgroup v2 بالفعل، يمكننا إعادة وصله بخيار nsdelegate كما يلي:

    mount -t cgroup2 -o remount,nsdelegate \
                     none /sys/fs/cgroup/unified

تأثير خيار الوصل هذا هو جعل نطاقات أسماء مجموعات التحكم تصبح آلياً حدوداً للتفويض. وبشكل أكثر تحديداً، تُطبق القيود التالية على العمليات داخل نطاق أسماء مجموعة التحكم:

•   ستفشل عمليات الكتابة إلى ملفات واجهة المتحكم في الدليل الجذر لنطاق الأسماء مع الخطأ EPERM. لا يزال بإمكان العمليات داخل نطاق أسماء مجموعة التحكم الكتابة إلى الملفات القابلة للتفويض في الدليل الجذر لنطاق أسماء مجموعة التحكم مثل cgroup.procs و cgroup.subtree_control، ويمكنها إنشاء هرمية فرعية تحت الدليل الجذر.

•   تُرفض محاولات نقل العمليات عبر حدود نطاق الأسماء (مع الخطأ ENOENT). لا يزال بإمكان العمليات داخل نطاق أسماء مجموعة التحكم (بشرط الالتزام بقواعد الاحتواء الموضحة أدناه) نقل العمليات بين مجموعات التحكم داخل الهرمية الفرعية تحت جذر نطاق الأسماء.

إن القدرة على تعريف نطاقات أسماء مجموعات التحكم كحدود للتفويض تجعل هذه النطاقات أكثر فائدة. ولفهم السبب، لنتصور أن لدينا بالفعل هرمية واحدة لمجموعة تحكم فُوِّضت لمستخدم غير متميز، cecilia، باستخدام تقنية التفويض الأقدم الموضحة أعلاه. ولنفترض أيضًا أن cecilia أرادت تفويض هرمية فرعية أخرى تحت الهرمية المفوَّضة الموجودة. (على سبيل المثال، قد تكون الهرمية المفوَّضة مرتبطة بحاوية غير متميزة تديرها cecilia.) حتى لو استُخدم نطاق أسماء مجموعة تحكم، فبسبب ملكية المستخدم غير المتميز cecilia لكلا الهرميتين، يمكن تنفيذ الإجراءات غير المشروعة التالية:

•   يمكن لعملية في الهرمية الدنيا تغيير إعدادات متحكم الموارد في الدليل الجذر لتلك الهرمية. (تهدف إعدادات متحكم الموارد هذه إلى السماح بممارسة التحكم من مجموعة التحكم الأب؛ ولا ينبغي السماح لعملية داخل مجموعة التحكم الابنة بتعديلها.)

•   يمكن لعملية داخل الهرمية الدنيا نقل العمليات من وإلى الهرمية الدنيا إذا كانت مجموعات التحكم في الهرمية العليا مرئية بطريقة ما.

يمنع استخدام خيار الوصل nsdelegate كلتا هاتين الإمكانيتين.

لا يكون لخيار الوصل nsdelegate تأثير إلا عند تنفيذه في نطاق أسماء الوصل الأولي؛ أما في نطاقات أسماء الوصل الأخرى، فيُتجاهل الخيار بصمت.

ملاحظة: في بعض الأنظمة، يقوم systemd(1) بوصّل نظام ملفات cgroup v2 آلياً. ومن أجل تجربة عملية nsdelegate، قد يكون من المفيد إقلاع النواة باستخدام خيارات سطر الأوامر التالية:

    cgroup_no_v1=all systemd.legacy_systemd_cgroup_controller

تؤدي هذه الخيارات إلى إقلاع النواة مع تعطيل متحكمات cgroups v1 (مما يعني أن المتحكمات ستكون متاحة في هرمية v2)، وتخبر systemd(1) بعدم وصل واستخدام هرمية cgroup v2، بحيث يمكن وصل هرمية v2 يدوياً مع الخيارات المطلوبة بعد الإقلاع.

  قواعد احتواء تفويض مجموعات التحكم
تضمن بعض قواعد احتواء التفويض أن المفوَّض إليه يمكنه نقل العمليات بين مجموعات التحكم داخل الشجرة الفرعية المفوَّضة، ولكن لا يمكنه نقل العمليات من خارج الشجرة الفرعية المفوَّضة إليها أو العكس. يمكن لعملية غير متميزة (أي المفوَّض إليه) كتابة معرف العملية (PID) لعملية "مستهدفة" في ملف cgroup.procs فقط إذا تحقق كل ما يلي:

•   يملك المستكتِب (المستدعي للكاتبة) إذن كتابة على ملف cgroup.procs في مجموعة التحكم الوجهة.

•   يملك المستكتِب إذن كتابة على ملف cgroup.procs في أقرب سلف مشترك لمجموعتي التحكم المصدر والوجهة. لاحظ أنه في بعض الحالات، قد يكون أقرب سلف مشترك هو مجموعة التحكم المصدر أو الوجهة نفسها. لا يُفرض هذا المتطلب في هرميات cgroups v1، ونتيجة لذلك فإن الاحتواء في الإصدار 1 أقل صرامة منه في الإصدار 2. (على سبيل المثال، في cgroups v1 يمكن للمستخدم الذي يملك هرميتين فرعيتين مفوضتين متميزتين نقل عملية بين الهرميتين.)

•   إذا وُصل نظام ملفات cgroup v2 مع خيار nsdelegate، فيجب أن يكون المستكتِب قادراً على رؤية مجموعتي التحكم المصدر والوجهة من نطاق أسماء مجموعة التحكم الخاص به.

•   في cgroups v1: يجب أن يطابق معرف المستخدم الفعلي (effective UID) للمستكتِب (أي المفوَّض إليه) معرف المستخدم الحقيقي أو معرف المستخدم المحفوظ (set-user-ID) للعملية المستهدفة. قبل لينكس 4.11، كان هذا المتطلب يُطبق أيضًا في cgroups v2 (كان هذا متطلباً تاريخياً موروثاً من cgroups v1 ثم اعتبر لاحقًا غير ضروري، لأن القواعد الأخرى تكفي للاحتواء في cgroups v2.)

ملاحظة: إحدى نتائج قواعد احتواء التفويض هذه هي أن المفوَّض إليه غير المتميز لا يمكنه وضع العملية الأولى في الشجرة الفرعية المفوَّضة؛ بل يجب على المفوِّض وضع العملية الأولى (عملية يملكها المفوَّض إليه) في الشجرة الفرعية المفوَّضة.

وضع الخيوط في الإصدار 2 من مجموعات التحكم
من بين القيود التي فرضها الإصدار 2 من مجموعات التحكم ولم تكن موجودة في الإصدار 1 ما يلي:

•   لا تحكم على مستوى الخيوط: يجب أن تكون جميع خيوط العملية في مجموعة التحكم نفسها.

•   لا عمليات داخلية: لا يمكن لمجموعة تحكم أن تضم عمليات أعضاء وتمارس التحكم عبر المتحكمات على مجموعات تحكم ابنة في الوقت نفسه.

أُضيف كلاً من هذين القيدين لأن غيابهما تسبب في مشاكل في cgroups v1. وبشكل خاص، فإن قدرة cgroups v1 على السماح بعضوية مجموعات التحكم على مستوى الخيوط لم تكن منطقية لبعض المتحكمات. (من الأمثلة البارزة متحكم الذاكرة: بما أن الخيوط تتشارك مساحة العناوين، لم يكن من المنطقي تقسيم الخيوط عبر مجموعات تحكم ذاكرة مختلفة.)

على الرغم من قرار التصميم الأولي في cgroups v2، كانت هناك حالات استخدام لمتحكمات معينة، لاسيما متحكم الوحدة المركزية (cpu)، حيث كان التحكم على مستوى الخيوط مفيداً وذا معنى. واستجابة لحالات الاستخدام هذه، أضاف لينكس 4.14 وضع الخيوط للإصدار 2 من مجموعات التحكم.

يسمح وضع الخيوط بما يلي:

•   إنشاء أشجار فرعية خيطية يمكن فيها توزيع خيوط العملية عبر مجموعات تحكم داخل الشجرة. (قد تحتوي الشجرة الفرعية الخيطية على عمليات متعددة الخيوط.)

•   مفهوم المتحكمات الخيطية، والتي يمكنها توزيع الموارد عبر مجموعات التحكم في شجرة فرعية خيطية.

•   تخفيف "قاعدة عدم وجود عمليات داخلية"، بحيث يمكن لمجموعة تحكم، ضمن شجرة فرعية خيطية، أن تحتوي على خيوط أعضاء وتمارس التحكم في الموارد على مجموعات التحكم الابنة.

مع إضافة وضع الخيوط، تحتوي كل مجموعة تحكم غير جذرية الآن على ملف جديد، cgroup.type، الذي يعرض "نوع" مجموعة التحكم، ويمكن استخدامه في بعض الظروف لتغييره. يحتوي هذا الملف على إحدى قيم الأنواع التالية:

domain
    هذه مجموعة تحكم عادية من الإصدار 2 توفر تحكماً على مستوى العمليات. إذا كانت العملية عضواً في مجموعة التحكم هذه، فإن جميع خيوط العملية تكون (بالتعريف) في مجموعة التحكم نفسها. هذا هو نوع مجموعة التحكم المبدئي، ويوفر السلوك نفسه الذي كان متاحاً لمجموعات التحكم في تطبيق cgroups v2 الأولي.

threaded
    هذه مجموعة تحكم هي عضو في شجرة فرعية خيطية. يمكن إضافة خيوط إلى مجموعة التحكم هذه، ويمكن تفعيل المتحكمات لها.

domain threaded
    هذه مجموعة تحكم نطاق تعمل كجذر لشجرة فرعية خيطية. يُعرف نوع مجموعة التحكم هذه أيضًا باسم "الجذر الخيطي".

domain invalid
    هذه مجموعة تحكم داخل شجرة فرعية خيطية تمر بحالة "غير صالحة". لا يمكن إضافة عمليات إليها، ولا يمكن تفعيل متحكمات لها. الشيء الوحيد الذي يمكن فعله بهذه المجموعة (بخلاف حذفها) هو تحويلها إلى مجموعة تحكم threaded عبر كتابة السلسلة "threaded" في ملف cgroup.type.

    الهدف من وجود هذا النوع "المؤقت" أثناء إنشاء شجرة فرعية خيطية (بدلاً من قيام النواة ببساطة وبشكل فوري بتحويل جميع مجموعات التحكم تحت الجذر الخيطي إلى النوع threaded) هو السماح بتوسعات مستقبلية ممكنة لنموذج وضع الخيوط.

  المتحكمات الخيطية مقابل متحكمات النطاق
مع إضافة وضع الخيوط، يميز الإصدار 2 من مجموعات التحكم الآن بين نوعين من متحكمات الموارد:

•   المتحكمات الخيطية: تدعم هذه المتحكمات التحكم في الموارد على مستوى الخيوط ويمكن تفعيلها داخل الأشجار الفرعية الخيطية، مما يؤدي لظهور ملفات واجهة المتحكم المقابلة داخل مجموعات التحكم في الشجرة الفرعية الخيطية. بحلول لينكس 4.19، المتحكمات التالية هي متحكمات خيطية: cpu و perf_event و pids.

•   متحكمات النطاق: تدعم هذه المتحكمات التحكم في الموارد على مستوى العمليات فقط. ومن منظور متحكم النطاق، تكون جميع خيوط العملية دوماً في مجموعة التحكم نفسها. لا يمكن تفعيل متحكمات النطاق داخل شجرة فرعية خيطية.

  إنشاء شجرة فرعية خيطية
يوجد مساران يؤديان إلى إنشاء شجرة فرعية خيطية. يسير المسار الأول كما يلي:

(1) نقوم بكتابة السلسلة "threaded" في ملف cgroup.type لمجموعة تحكم y/z التي يكون نوعها حالياً domain. يؤدي هذا للآثار التالية:

    •   يصبح نوع مجموعة التحكم y/z هو threaded.

    •   يصبح نوع مجموعة التحكم الأب، y، هو domain threaded. مجموعة التحكم الأب هي جذر الشجرة الفرعية الخيطية (وتعرف أيضًا باسم "الجذر الخيطي").

    •   تُحوَّل جميع مجموعات التحكم الأخرى تحت y التي لم تكن بالفعل من النوع threaded (لأنها كانت داخل أشجار فرعية خيطية موجودة مسبقاً تحت الجذر الخيطي الجديد) إلى النوع domain invalid. وأي مجموعات تحكم تُنشأ لاحقًا تحت y ستأخذ أيضًا النوع domain invalid.

(2) نقوم بكتابة السلسلة "threaded" في كل من مجموعات التحكم ذات النوع domain invalid تحت y، من أجل تحويلها إلى النوع threaded. ونتيجة لهذه الخطوة، تصبح جميع الخيوط تحت الجذر الخيطي من النوع threaded وتصبح الشجرة الفرعية الخيطية الآن صالحة للاستخدام بالكامل. إن متطلب كتابة "threaded" لكل مجموعة تحكم مرهق نوعاً ما، لكنه يسمح بتوسعات مستقبلية لنموذج وضع الخيوط.

الطريقة الثانية لإنشاء شجرة فرعية خيطية هي كما يلي:

(1) في مجموعة تحكم موجودة، z، نوعها حالياً هو domain، نقوم (1.1) بتفعيل متحكم خيطي واحد أو أكثر و (1.2) بجعل عملية ما عضواً في z. (يمكن تنفيذ هاتين الخطوتين بأي ترتيب.) يؤدي هذا للنتائج التالية:

    •   يصبح نوع z هو domain threaded.

    •   تُحوَّل جميع مجموعات التحكم المتحدرة من z والتي لم تكن بالفعل من النوع threaded إلى النوع domain invalid.

(2) كما في السابق، نجعل الشجرة الفرعية الخيطية صالحة للاستخدام عبر كتابة السلسلة "threaded" في كل من مجموعات التحكم domain invalid تحت z، لتحويلها إلى النوع threaded.

إحدى نتائج المسارات المذكورة أعلاه لإنشاء شجرة فرعية خيطية هي أن مجموعة التحكم الجذر الخيطية يمكن أن تكون أماً لمجموعات تحكم threaded (و domain invalid) فقط. ولا يمكن لمجموعة التحكم الجذر الخيطية أن تكون أماً لمجموعة تحكم domain، كما لا يمكن لمجموعة تحكم threaded أن تملك شقيقة من نوع domain.

  استخدام شجرة فرعية خيطية
داخل الشجرة الفرعية الخيطية، يمكن تفعيل المتحكمات الخيطية في كل مجموعة فرعية غُيِّر نوعها إلى threaded؛ وعند القيام بذلك، تظهر ملفات واجهة المتحكم المقابلة في أبناء مجموعة التحكم تلك.

يمكن نقل عملية إلى شجرة فرعية خيطية عبر كتابة معرف العملية (PID) في ملف cgroup.procs في إحدى مجموعات التحكم داخل الشجرة. يؤدي هذا لجعل جميع خيوط العملية أعضاء في مجموعة التحكم المقابلة ويجعل العملية عضواً في الشجرة الفرعية الخيطية. يمكن بعد ذلك توزيع خيوط العملية عبر الشجرة الفرعية الخيطية عبر كتابة معرفات الخيوط (انظر gettid(2)) في ملفات cgroup.threads في مجموعات تحكم مختلفة داخل الشجرة. يجب أن تقيم جميع خيوط العملية في الشجرة الفرعية الخيطية نفسها.

كما هو الحال مع الكتابة في cgroup.procs، تُطبق بعض قواعد الاحتواء عند الكتابة في ملف cgroup.threads:

•   يجب أن يملك المستكتِب إذن كتابة على ملف cgroup.threads في مجموعة التحكم الوجهة.

•   يجب أن يملك المستكتِب إذن كتابة على ملف cgroup.procs في السلف المشترك لمجموعتي التحكم المصدر والوجهة. (في بعض الحالات، قد يكون السلف المشترك هو مجموعة التحكم المصدر أو الوجهة نفسها.)

•   يجب أن تكون مجموعتا التحكم المصدر والوجهة في الشجرة الفرعية الخيطية نفسها. (خارج الشجرة الفرعية الخيطية، تفشل محاولة نقل خيط عبر كتابة معرفه في ملف cgroup.threads في مجموعة تحكم domain مختلفة مع الخطأ EOPNOTSUPP.)

يتوفر ملف cgroup.threads في كل مجموعة تحكم (بما في ذلك مجموعات نطاق domain) ويمكن قراءته لاكتشاف مجموعة الخيوط الموجودة في مجموعة التحكم. لا تضمن معرفات الخيوط الناتجة عن قراءة هذا الملف أن تكون مرتبة أو خالية من التكرار.

يعرض ملف cgroup.procs في الجذر الخيطي معرفات العمليات (PIDs) لجميع العمليات التي هي أعضاء في الشجرة الفرعية الخيطية. ملفات cgroup.procs في مجموعات التحكم الأخرى في الشجرة غير قابلة للقراءة.

لا يمكن تفعيل متحكمات النطاق في شجرة فرعية خيطية؛ ولا تظهر أي ملفات واجهة متحكم داخل مجموعات التحكم تحت الجذر الخيطي. ومن منظور متحكم النطاق، تكون الأشجار الفرعية الخيطية غير مرئية: تظهر العملية متعددة الخيوط داخل شجرة فرعية خيطية لمتحكم النطاق كعملية تقيم في مجموعة تحكم الجذر الخيطية.

داخل الشجرة الفرعية الخيطية، لا تُطبق قاعدة "عدم وجود عمليات داخلية": حيث يمكن لمجموعة التحكم أن تحتوي على عمليات أعضاء (أو خيوط) وتمارس التحكم عبر المتحكمات في المجموعات الابنة في آن واحد.

  قواعد الكتابة في cgroup.type وإنشاء أشجار فرعية خيطية
تُطبق مجموعة من القواعد عند الكتابة في ملف cgroup.type:

•   لا يمكن كتابة سوى السلسلة "threaded". وبعبارة أخرى، الانتقال الصريح الوحيد الممكن هو تحويل مجموعة تحكم domain إلى النوع threaded.

•   يعتمد أثر كتابة "threaded" على القيمة الحالية في cgroup.type، كما يلي:

    •   domain أو domain threaded: بدء إنشاء شجرة فرعية خيطية (جذرها هو أب مجموعة التحكم هذه) عبر المسار الأول الموصوف أعلاه؛

    •   domain invalid: تحويل مجموعة التحكم هذه (الموجودة داخل شجرة فرعية خيطية) إلى حالة صالحة للاستخدام (أي threaded)؛

    •   threaded: لا يوجد تأثير (عملية فارغة).

•   لا يمكننا الكتابة في ملف cgroup.type إذا كان نوع الأب هو domain invalid. وبعبارة أخرى، يجب تحويل مجموعات التحكم في شجرة فرعية خيطية إلى حالة threaded من الأعلى إلى الأسفل.

هناك أيضًا بعض القيود التي يجب استيفاؤها لإنشاء شجرة فرعية خيطية جذرها مجموعة التحكم x:

•   يجب ألا توجد أي عمليات أعضاء في مجموعات التحكم المتحدرة من x. (يمكن لمجموعة التحكم x نفسها أن تضم عمليات أعضاء.)

•   يجب عدم تفعيل أي متحكمات نطاق في ملف cgroup.subtree_control الخاص بـ x.

إذا نُقض أي من القيود المذكورة أعلاه، فإن محاولة كتابة "threaded" في ملف cgroup.type ستفشل مع الخطأ ENOTSUP.

  نوع مجموعة التحكم "domain threaded"
وفقاً للمسارات الموضحة أعلاه، يمكن أن يتغير نوع مجموعة التحكم إلى domain threaded في أي من الحالتين التاليتين:

•   كتابة السلسلة "threaded" في مجموعة تحكم ابنة.

•   تفعيل متحكم خيطي داخل مجموعة التحكم وجعل عملية ما عضواً فيها.

يمكن لمجموعة تحكم domain threaded، وليكن اسمها x، أن تعود إلى النوع domain إذا لم تعد الشروط المذكورة أعلاه قائمة - أي إذا حُذفت جميع مجموعات التحكم الابنة threaded لـ x، ولم يعد x يمتلك متحكمات خيطية مفعلة أو لم يعد يضم عمليات أعضاء.

عندما تعود مجموعة تحكم domain threaded x إلى النوع domain:

•   تعود جميع المجموعات المتحدرة domain invalid من x والتي ليست في أشجار فرعية خيطية بمستوى أدنى إلى النوع domain.

•   تعود مجموعات التحكم الجذرية في أي أشجار فرعية خيطية بمستوى أدنى إلى النوع domain threaded.

  استثناءات لمجموعة التحكم (cgroup) الرئيسة
تُعامل مجموعة التحكم (cgroup) الرئيسة في التسلسل الهرمي للإصدار الثاني معاملة استثنائية: إذ يمكن أن تكون أصلاً لكل من مجموعات التحكم domain و threaded. إذا كُتبت السلسلة "threaded" إلى ملف cgroup.type لأحد فروع مجموعة التحكم الرئيسة، فإن:

•   نوع مجموعة التحكم تلك يصبح threaded.

•   نوع أي سليل لمجموعة التحكم تلك التي ليست جزءاً من أشجار فرعية مسلسلة (threaded) ذات مستوى أدنى يتغير إلى domain invalid.

لاحظ أنه في هذه الحالة، لا توجد مجموعة تحكم يصبح نوعها domain threaded. (نظرياً، يمكن اعتبار مجموعة التحكم الرئيسة كأصل متسلسل لمجموعة التحكم التي تغير نوعها إلى threaded.)

الهدف من هذه المعاملة الاستثنائية لمجموعة التحكم الرئيسة هو السماح لمجموعة تحكم مسلسلة (threaded) تستخدم متحكم cpu بأن تُوضع في أعلى مكان ممكن في التسلسل الهرمي، وذلك لتقليل التكلفة (الصغيرة) لعبور التسلسل الهرمي لمجموعات التحكم.

  متحكم "cpu" في مجموعات التحكم v2 والخيوط في الوقت الحقيقي
بدءاً من لينكس 4.19، لا يدعم متحكم cpu في الإصدار الثاني لمجموعات التحكم التحكم في خيوط الوقت الحقيقي (تحديداً الخيوط المجدولة تحت أي من سياسات SCHED_FIFO، و SCHED_RR، والموصوفة في SCHED_DEADLINE؛ انظر sched(7)). لذا، يمكن تفعيل متحكم cpu في مجموعة التحكم الرئيسة فقط إذا كانت جميع خيوط الوقت الحقيقي موجودة في مجموعة التحكم الرئيسة. (إذا وجدت خيوط وقت حقيقي في مجموعات تحكم غير رئيسة، فإن عملية الكتابة write(2) للسلسلة "+cpu" إلى ملف cgroup.subtree_control ستفشل بالخطأ EINVAL.)

في بعض الأنظمة، يضع systemd(1) خيوط وقت حقيقي معينة في مجموعات تحكم غير رئيسة في التسلسل الهرمي للإصدار الثاني. في مثل هذه الأنظمة، يجب نقل هذه الخيوط أولاً إلى مجموعة التحكم الرئيسة قبل تمكين متحكم cpu.

الأخطاء
يمكن أن تحدث الأخطاء التالية لعملية الوصل mount(2):

EBUSY
    محاولة لوصل نظام ملفات مجموعة التحكم الإصدار الأول لم تحدد خيار name= (لوصل تسلسل هرمي مسمى) ولا اسم المتحكم (أو all).

ملاحظات
ترث العملية الابنة المنشأة عبر fork(2) عضويات مجموعة التحكم (cgroup) الخاصة بوالدها. تُحفظ عضويات مجموعة التحكم للعملية عبر execve(2).

يمكن استخدام علم CLONE_INTO_CGROUP في clone3(2) لإنشاء عملية ابنة تبدأ حياتها في مجموعة تحكم مختلفة من الإصدار الثاني عن العملية الوالدة.

  ملفات /proc

/proc/cgroups (منذ لينكس 2.6.24)
    يحتوي هذا الملف على معلومات حول المتحكمات المجمعة داخل النواة. مثال على محتويات هذا الملف (أعيد تنسيقه لتسهيل القراءة) هو كالتالي:

        #subsys_name    hierarchy      num_cgroups    enabled
        cpuset          4              1              1
        cpu             8              1              1
        cpuacct         8              1              1
        blkio           6              1              1
        memory          3              1              1
        devices         10             84             1
        freezer         7              1              1
        net_cls         9              1              1
        perf_event      5              1              1
        net_prio        9              1              1
        hugetlb         0              1              0
        pids            2              1              1

    الحقول في هذا الملف هي، من اليسار إلى اليمين:

    [1] اسم المتحكم.

    [2] المعرف الفريد لتسلسل مجموعة التحكم الهرمي الذي وُصل عليه هذا المتحكم. إذا رُبطت متحكمات متعددة من الإصدار الأول بنفس التسلسل الهرمي، فسيظهر لكل منها نفس معرف التسلسل الهرمي في هذا الحقل. ستكون القيمة في هذا الحقل 0 إذا:

        •   لم يُوصل المتحكم على تسلسل هرمي لمجموعات التحكم من الإصدار الأول؛

        •   رُبط المتحكم بالتسلسل الهرمي الموحد الوحيد لمجموعات التحكم من الإصدار الثاني؛ أو

        •   عُطّل المتحكم (انظر أدناه).

    [3] عدد مجموعات التحكم في هذا التسلسل الهرمي التي تستخدم هذا المتحكم.

    [4] يحتوي هذا الحقل على القيمة 1 إذا كان هذا المتحكم مُمكّناً، أو 0 إذا كان قد عُطّل (عبر معطى سطر أوامر تمهيد النواة cgroup_disable).

/proc/pid/cgroup (منذ لينكس 2.6.24)
    يصف هذا الملف مجموعات التحكم التي تنتمي إليها العملية ذات معرف العملية (PID) المقابل. تختلف المعلومات المعروضة لتسلسلات مجموعات التحكم الهرمية للإصدار الأول والإصدار الثاني.

    لكل تسلسل هرمي لمجموعات التحكم تكون العملية عضواً فيه، يوجد مدخل واحد يحتوي على ثلاثة حقول مفصولة بنقطتين رأسيين:

        hierarchy-ID:controller-list:cgroup-path

    على سبيل المثال:

        5:cpuacct,cpu,cpuset:/daemons

    الحقول المفصولة بنقطتين رأسيين هي، من اليسار إلى اليمين:

    [1] بالنسبة لتسلسلات مجموعات التحكم الهرمية من الإصدار الأول، يحتوي هذا الحقل على رقم معرف تسلسل هرمي فريد يمكن مطابقته مع معرف تسلسل هرمي في /proc/cgroups. بالنسبة لتسلسل مجموعات التحكم الهرمي من الإصدار الثاني، يحتوي هذا الحقل على القيمة 0.

    [2] بالنسبة لتسلسلات مجموعات التحكم الهرمية من الإصدار الأول، يحتوي هذا الحقل على قائمة مفصولة بفاصلة للمتحكمات المربوطة بالتسلسل الهرمي. بالنسبة لتسلسل مجموعات التحكم الهرمي من الإصدار الثاني، يكون هذا الحقل فارغاً.

    [3] يحتوي هذا الحقل على مسار مجموعة التحكم في التسلسل الهرمي التي تنتمي إليها العملية. هذا المسار نسبي لنقطة وصل التسلسل الهرمي.

  ملفات /sys/kernel/cgroup

/sys/kernel/cgroup/delegate (منذ لينكس 4.15)
    يصدّر هذا الملف قائمة بملفات مجموعات التحكم v2 (ملف واحد في كل سطر) القابلة للتفويض (أي التي يجب تغيير ملكيتها إلى معرف المستخدم للمُفوَّض إليه). في المستقبل، قد تتغير أو تنمو مجموعة الملفات القابلة للتفويض، ويوفر هذا الملف طريقة للنواة لإبلاغ تطبيقات فضاء المستخدم بالملفات التي يجب تفويضها. كما في لينكس 4.15، يظهر التالي عند فحص هذا الملف:

        $ cat /sys/kernel/cgroup/delegate
        cgroup.procs
        cgroup.subtree_control
        cgroup.threads

/sys/kernel/cgroup/features (منذ لينكس 4.15)
    بمرور الوقت، قد تتغير أو تنمو مجموعة ميزات مجموعات التحكم v2 التي توفرها النواة، أو قد لا تكون بعض الميزات مُمكّنة بشكل مبدئي. يوفر هذا الملف طريقة لتطبيقات فضاء المستخدم لاكتشاف الميزات التي تدعمها النواة المشغلة والتم تفعيلها. تُدرج الميزات ميزة واحدة في كل سطر:

        $ cat /sys/kernel/cgroup/features
        nsdelegate
        memory_localevents

    المدخلات التي يمكن أن تظهر في هذا الملف هي:

    memory_localevents (منذ لينكس 5.2)
        تدعم النواة خيار الوصل memory_localevents.

    nsdelegate (منذ لينكس 4.15)
        تدعم النواة خيار الوصل nsdelegate.

    memory_recursiveprot (منذ لينكس 5.7)
        تدعم النواة خيار الوصل memory_recursiveprot.

انظر أيضًا
prlimit(1), systemd(1), systemd-cgls(1), systemd-cgtop(1), clone(2), ioprio_set(2), perf_event_open(2), setrlimit(2), cgroup_namespaces(7), cpuset(7), namespaces(7), sched(7), user_namespaces(7)

ملف مصدر النواة Documentation/admin-guide/cgroup-v2.rst.

ترجمة
تُرجمت هذه الصفحة من الدليل بواسطة زايد السعيدي <zayed.alsaidi@gmail.com>

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 (https://www.gnu.org/licenses/gpl-3.0.html) أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

إذا وجدت أي أخطاء في ترجمة صفحة الدليل هذه، يرجى إرسال بريد إلكتروني إلى قائمة بريد المترجمين: kde-l10n-ar@kde.org.