Scroll to navigation

fcntl(2) System Calls Manual fcntl(2)

الاسم

fcntl - التلاعب بواصف الملف

المكتبة

مكتبة سي المعيارية (libc، -lc)

موجز

#include <fcntl.h>
int fcntl(int fd, int op, ... /* arg */ );

الوصف

تجري fcntl() إحدى العمليات الموصوفة أدناه على واصف الملف المفتوح fd. تُحدد العملية بواسطة op.

يمكن لـ fcntl() أن تأخذ وسيطًا ثالثًا اختياريًا. ويُحدد ما إذا كان هذا الوسيط مطلوبًا أم لا بواسطة op. يشار إلى نوع الوسيط المطلوب بين قوسين بعد كل اسم op (في معظم الحالات، النوع المطلوب هو int، ونحدد الوسيط باستخدام الاسم arg)، أو يتم تحديد void إذا لم يكن الوسيط مطلوبًا.

تُدعم بعض العمليات أدناه فقط بدءًا من إصدار معين من نواة لينكس. الطريقة المفضلة للتحقق مما إذا كانت نواة المضيف تدعم عملية معينة هي استدعاء fcntl() مع قيمة op المطلوبة، ثم اختبار ما إذا كان الاستدعاء قد فشل مع الخطأ EINVAL، مما يشير إلى أن النواة لا تتعرف على هذه القيمة.

مضاعفة واصف ملف

مضاعفة واصف الملف fd باستخدام أصغر واصف ملف متاح برقم أكبر من أو يساوي arg. يختلف هذا عن dup2(2)، التي تستخدم واصف الملف المحدد بالضبط.
عند النجاح، يُعاد واصف الملف الجديد.
انظر dup(2) لمزيد من التفاصيل.
كما في F_DUPFD، ولكن بالإضافة إلى ذلك تُضبط لصيقة الإغلاق عند التنفيذ (close-on-exec) لواصف الملف المضاعف. يتيح تحديد هذه اللصيقة للبرنامج تجنب عملية fcntl() F_SETFD إضافية لضبط لصيقة FD_CLOEXEC. لشرح سبب فائدة هذه اللصيقة، انظر وصف O_CLOEXEC في open(2).

لصائق واصف الملف

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

إعادة لصائق واصف الملف (كنتيجة للدالة)؛ ويُتجاهل arg.
ضبط لصائق واصف الملف على القيمة المحددة بواسطة arg.

في البرامج متعددة الخيوط، يكون استخدام fcntl() F_SETFD لضبط لصيقة الإغلاق عند التنفيذ في نفس الوقت الذي يقوم فيه خيط آخر بعملية fork(2) بالإضافة إلى execve(2) عرضة لحالة تسابق قد تسرب واصف الملف دون قصد إلى البرنامج المنفذ في العملية الابنة. انظر مناقشة لصيقة O_CLOEXEC في open(2) للحصول على التفاصيل وعلاج للمشكلة.

لصائق حالة الملف

لكل وصف ملف مفتوح لصائق حالة مرتبطة به، تُهيأ بواسطة open(2) وربما تُعدل بواسطة fcntl(). واصفات الملفات المضاعفة (التي تم إنشاؤها باستخدام dup(2) و fcntl(F_DUPFD) و fork(2) وما إلى ذلك) تشير إلى نفس وصف الملف المفتوح، وبالتالي تتشارك في نفس لصائق حالة الملف.

تم وصف لصائق حالة الملف ودلالاتها في open(2).

إعادة وضع الوصول إلى الملف ولصائق حالة الملف (كنتيجة للدالة)؛ ويُتجاهل arg.
F_SETFL (int)
ضبط لصائق حالة الملف على القيمة المحددة بواسطة arg. يتم تجاهل وضع الوصول إلى الملف (O_RDONLY و O_WRONLY و O_RDWR) ولصائق إنشاء الملف (أي O_CREAT و O_EXCL و O_NOCTTY و O_TRUNC) في arg. في لينكس، يمكن لهذه العملية تغيير لصائق O_APPEND و O_ASYNC و O_DIRECT و O_NOATIME و O_NONBLOCK فقط. لا يمكن تغيير لصيقتي O_DSYNC و O_SYNC؛ انظر قسم العلل (BUGS) أدناه.

قفل السجلات الاستشاري

تنفذ لينكس أقفال سجلات يونكس (UNIX) التقليدية ("المرتبطة بالعملية")، كما هو معياري في POSIX. لبديل مخصص للينكس ذو دلالات أفضل، انظر مناقشة أقفال وصف الملف المفتوح أدناه.

تُستخدم F_SETLK و F_SETLKW و F_GETLK للاستحواذ على أقفال السجلات، وتحريرها، واختبار وجودها (تُعرف أيضًا بأقفال نطاق-البايت، أو قطاع-الملف، أو منطقة-الملف). المعامل الثالث، lock، هو مؤشر إلى بنية تحتوي على الأقل على الحقول التالية (بترتيب غير محدد).


struct flock {

...
short l_type; /* نوع القفل: F_RDLCK,
F_WRLCK, F_UNLCK */
short l_whence; /* كيفية تفسير l_start:
SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start; /* إزاحة البداية للقفل */
off_t l_len; /* عدد البايتات المراد قفلها */
pid_t l_pid; /* معرف العملية (PID) التي تمنع قفلنا
(يُضبط بواسطة F_GETLK و F_OFD_GETLK) */
... };

تحدد حقول l_whence و l_start و l_len في هذه البنية نطاق البايتات التي نرغب في قفلها. يمكن قفل البايتات التي تتجاوز نهاية الملف، ولكن لا يمكن قفل البايتات التي تسبق بداية الملف.

تمثل l_start إزاحة البداية للقفل، وتُفسّر بالنسبة إلى: إما بداية الملف (إذا كانت l_whence هي SEEK_SET)؛ أو إزاحة الملف الحالية (إذا كانت l_whence هي SEEK_CUR)؛ أو نهاية الملف (إذا كانت l_whence هي SEEK_END). في الحالتين الأخيرتين، يمكن أن تكون l_start رقمًا سالبًا بشرط ألا تقع الإزاحة قبل بداية الملف.

تحدد l_len عدد البايتات المراد قفلها. إذا كانت l_len موجبة، فإن النطاق المراد قفله يغطي البايتات من l_start صعودًا إلى l_start+l_len-1 (بما في ذلك هذا الأخير). لتحديد 0 لقيمة l_len معنى خاص: قفل جميع البايتات بدءًا من الموقع المحدد بواسطة l_whence و l_start وصولاً إلى نهاية الملف، بغض النظر عن مدى كبر حجم الملف.

يسمح POSIX.1-2001 (لكنه لا يتطلب) للتنفيذ بدعم قيمة l_len سالبة؛ إذا كانت l_len سالبة، فإن الفترة الموضحة بواسطة lock تغطي البايتات من l_start+l_len صعودًا إلى l_start-1 (بما في ذلك هذا الأخير). دُعم هذا منذ لينكس 2.4.21 ولينكس 2.5.49.

يمكن استخدام حقل l_type لوضع قفل قراءة (F_RDLCK) أو قفل كتابة (F_WRLCK) على ملف. يمكن لأي عدد من العمليات حيازة قفل قراءة (قفل مشترك) على منطقة ملف، ولكن يمكن لعملية واحدة فقط حيازة قفل كتابة (قفل حصري). يستبعد القفل الحصري جميع الأقفال الأخرى، سواء كانت مشتركة أو حصرية. يمكن لعملية واحدة حيازة نوع واحد فقط من الأقفال على منطقة ملف؛ إذا وُضع قفل جديد على منطقة مقفولة بالفعل، فسيُحوّل القفل الحالي إلى نوع القفل الجديد. (قد تتضمن مثل هذه التحويلات تقسيم القفل، أو تقليصه، أو دمجه مع قفل موجود إذا كان نطاق البايت المحدد بواسطة القفل الجديد لا يتطابق تمامًا مع نطاق القفل الحالي).

الاستحواذ على قفل (عندما يكون l_type هو F_RDLCK أو F_WRLCK) أو تحرير قفل (عندما يكون l_type هو F_UNLCK) على البايتات المحددة بواسطة حقول l_whence و l_start و l_len للمعامل lock. إذا كانت هناك عملية أخرى تحوز قفلاً متعارضًا، فإن هذا الاستدعاء يعيد -1 ويضبط errno على EACCES أو EAGAIN. (يختلف الخطأ المعاد في هذه الحالة عبر التنفيذات، لذا يتطلب POSIX من التطبيقات المحمولة التحقق من كلا الخطأين).
كما هو الحال في F_SETLK، ولكن إذا كان هناك قفل متعارض محوز على الملف، فانتظر حتى يُحرّر ذلك القفل. إذا التُقطت إشارة أثناء الانتظار، فسيُقاطع الاستدعاء ويعيد (بعد عودة معالج الإشارة) القيمة فوريًا (مع قيمة إرجاع -1 وضبط errno على EINTR؛ انظر signal(7)).
عند إدخال هذا الاستدعاء، يصف lock القفل الذي نود وضعه على الملف. إذا كان بالإمكان وضع القفل، فإن fcntl() لا يضعه فعليًا، بل يعيد F_UNLCK في حقل l_type من lock ويترك الحقول الأخرى للبنية دون تغيير.
إذا كان هناك قفل أو أكثر غير متوافق يمنع وضع هذا القفل، فإن fcntl() يعيد تفاصيل حول أحد تلك الأقفال في حقول l_type و l_whence و l_start و l_len من lock. إذا كان القفل المتعارض قفل سجل تقليدي (مرتبط بالعملية)، فسيُضبط حقل l_pid على PID العملية التي تحوز ذلك القفل. أما إذا كان القفل المتعارض قفل وصف ملف مفتوح، فسيُضبط l_pid على -1. لاحظ أن المعلومات المعادة قد تكون قديمة بالفعل بحلول الوقت الذي يفحصها فيه المستدعِي.

لوضع قفل قراءة، يجب أن يكون fd مفتوحًا للقراءة. ولوضع قفل كتابة، يجب أن يكون fd مفتوحًا للكتابة. ولوضع كلا النوعين من الأقفال، افتح الملف للقراءة والكتابة.

عند وضع أقفال باستخدام F_SETLKW، تكتشف الـ نواة "حالات الاستعصاء" (deadlocks)، حيث يتم حظر طلبات قفل عمليتين أو أكثر بشكل متبادل بواسطة أقفال تحوزها العمليات الأخرى. على سبيل المثال، افترض أن العملية (أ) تحوز قفل كتابة على البايت 100 من ملف، والعملية (ب) تحوز قفل كتابة على البايت 200. إذا حاولت كل عملية بعد ذلك قفل البايت المقفل بالفعل من قبل العملية الأخرى باستخدام F_SETLKW، فبدون اكتشاف الاستعصاء، ستظل كلتا العمليتين محظورتين إلى أجل غير مسمى. عندما تكتشف الـ نواة مثل هذه الحالات، فإنها تؤدي إلى فشل أحد طلبات القفل المحظورة فوريًا مع الخطأ EDEADLK؛ يجب على التطبيق الذي يواجه مثل هذا الخطأ تحرير بعض أقفاله للسماح للتطبيقات الأخرى بالمتابعة قبل محاولة استعادة الأقفال التي يتطلبها. تكتشف أيضًا حالات الاستعصاء الدائرية التي تشمل أكثر من عمليتين. لاحظ، مع ذلك، أن هناك قيودًا على خوارزمية اكتشاف الاستعصاء في الـ نواة؛ انظر قسم BUGS.

بالإضافة إلى إزالتها بواسطة F_UNLCK صريح، تُحرّر أقفال السجلات آليًا عند انتهاء العملية.

لا تُرث أقفال السجلات من قبل عملية ابن أُنشئت عبر fork(2)، ولكن يُحتفظ بها عبر execve(2).

بسبب التخزين المؤقت الذي تقوم به مكتبة stdio(3)، يجب تجنب استخدام قفل السجلات مع الدوال الموجودة في تلك الحزمة؛ استخدم read(2) و write(2) بدلاً من ذلك.

أقفال السجلات الموضحة أعلاه مرتبطة بالعملية (على عكس أقفال وصف الملف المفتوح الموضحة أدناه). وهذا له بعض العواقب المؤسفة:

إذا أغلقت عملية أي واصف ملف يشير إلى ملف، فستُحرّر جميع أقفال العملية على ذلك الملف، بغض النظر عن واصف (أو واصفات) الملف التي استُخدمت للحصول على الأقفال. هذا أمر سيئ: فهذا يعني أن العملية يمكن أن تفقد أقفالها على ملف مثل /etc/passwd أو /etc/mtab عندما تقرر دالة مكتبة لسبب ما فتح وقراءة وإغلاق نفس الملف.
تتشارك الخيوط في العملية الأقفال. بعبارة أخرى، لا يمكن لبرنامج متعدد الخيوط استخدام قفل السجلات لضمان عدم وصول الخيوط في نفس الوقت إلى نفس المنطقة من الملف.

تحل أقفال وصف الملف المفتوح كلتا المشكلتين.

أقفال وصف الملف المفتوح (ليست ضمن POSIX)

أقفال وصف الملف المفتوح هي أقفال نطاق-بايت استشارية تتطابق في معظم جوانبها مع أقفال السجلات التقليدية الموضحة أعلاه. هذا النوع من الأقفال مخصص للينكس، ومتاح منذ لينكس 3.15. (يوجد اقتراح مع مجموعة أوستن Austin Group لتضمين هذا النوع من الأقفال في المراجعة القادمة لـ POSIX.1). لشرح أوصاف الملفات المفتوحة، انظر open(2).

الفرق الرئيس بين نوعي الأقفال هو أنه بينما ترتبط أقفال السجلات التقليدية بالعملية، ترتبط أقفال وصف الملف المفتوح بوصف الملف المفتوح الذي اكتُسبت عليه، تمامًا مثل الأقفال المكتسبة باستخدام flock(2). وبالتالي (وعلى عكس أقفال السجلات الاستشارية التقليدية)، تُرث أقفال وصف الملف المفتوح عبر fork(2)clone(2) مع CLONE_FILES)، وتُحرّر آليًا فقط عند الإغلاق الأخير لوصف الملف المفتوح، بدلاً من تحريرها عند أي إغلاق للملف.

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

أقفال وصف الملف المفتوح التي توضع عبر نفس وصف الملف المفتوح (أي عبر نفس واصف الملف، أو عبر نسخة من واصف الملف أُنشئت بواسطة fork(2) أو dup(2) أو fcntl() F_DUPFD، وما إلى ذلك) تكون دائمًا متوافقة: إذا وُضع قفل جديد على منطقة مقفولة بالفعل، فسيُحوّل القفل الحالي إلى نوع القفل الجديد. (قد تؤدي مثل هذه التحويلات إلى تقسيم القفل، أو تقليصه، أو دمجه مع قفل موجود كما نُوقش أعلاه).

من ناحية أخرى، قد تتعارض أقفال وصف الملف المفتوح مع بعضها البعض عندما تُكتسب عبر أوصاف ملفات مفتوحة مختلفة. وبالتالي، يمكن للخيوط في برنامج متعدد الخيوط استخدام أقفال وصف الملف المفتوح لمزامنة الوصول إلى منطقة ملف عن طريق قيام كل خيط بإجراء open(2) خاص به على الملف وتطبيق الأقفال عبر واصف الملف الناتج.

كما هو الحال مع الأقفال الاستشارية التقليدية، فإن المعامل الثالث لـ fcntl()، وهو lock، هو مؤشر إلى بنية flock. وبخلاف أقفال السجلات التقليدية، يجب ضبط حقل l_pid لتلك البنية على الصفر عند استخدام العمليات الموضحة أدناه.

العمليات المخصصة للتعامل مع أقفال وصف الملف المفتوح مماثلة لتلك المستخدمة مع الأقفال التقليدية:

الاستحواذ على قفل وصف ملف مفتوح (عندما يكون l_type هو F_RDLCK أو F_WRLCK) أو تحرير قفل وصف ملف مفتوح (عندما يكون l_type هو F_UNLCK) على البايتات المحددة بواسطة حقول l_whence و l_start و l_len للمعامل lock. إذا كانت هناك عملية أخرى تحوز قفلاً متعارضًا، فإن هذا الاستدعاء يعيد -1 ويضبط errno على EAGAIN.
كما هو الحال في F_OFD_SETLK، ولكن إذا كان هناك قفل متعارض محوز على الملف، فانتظر حتى يُحرّر ذلك القفل. إذا التُقطت إشارة أثناء الانتظار، فسيُقاطع الاستدعاء ويعيد (بعد عودة معالج الإشارة) القيمة فوريًا (مع قيمة إرجاع -1 وضبط errno على EINTR؛ انظر signal(7)).
عند إدخال هذا الاستدعاء، يصف lock قفل وصف ملف مفتوح نود وضعه على الملف. إذا كان بالإمكان وضع القفل، فإن fcntl() لا يضعه فعليًا، بل يعيد F_UNLCK في حقل l_type من lock ويترك الحقول الأخرى للبنية دون تغيير. إذا كان هناك قفل أو أكثر غير متوافق يمنع وضع هذا القفل، فستُعاد تفاصيل حول أحد هذه الأقفال عبر lock، كما هو موضح أعلاه لـ F_GETLK.

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

القفل الإلزامي

تحذير: تنفيذ لينكس للقفل الإلزامي غير موثوق به. انظر قسم BUGS أدناه. بسبب هذه العيوب، وحقيقة أنه يُعتقد أن هذه الميزة قليلة الاستخدام، فقد أُصبح القفل الإلزامي ميزة اختيارية منذ لينكس 4.5، يحكمها خيار الضبط (CONFIG_MANDATORY_FILE_LOCKING). لم تعد هذه الميزة مدعومة على الإطلاق في لينكس 5.15 وما فوق.

بشكل مبدئي، تكون كل من أقفال السجلات التقليدية (المرتبطة بالعملية) وأقفال وصف الملف المفتوح استشارية. الأقفال الاستشارية لا تُفرض وهي مفيدة فقط بين العمليات المتعاونة.

يمكن أن يكون كلا نوعي القفل إلزاميين أيضًا. تُفرض الأقفال الإلزامية على جميع العمليات. إذا حاولت عملية إجراء وصول غير متوافق (مثل read(2) أو write(2)) على منطقة ملف بها قفل إلزامي غير متوافق، فإن النتيجة تعتمد على ما إذا كان علم O_NONBLOCK مفعلاً لوصف الملف المفتوح الخاص بها. إذا لم يكن علم O_NONBLOCK مفعلاً، فسيُحظر استدعاء النظام حتى يُزال القفل أو يُحوّل إلى وضع متوافق مع الوصول. إذا كان علم O_NONBLOCK مفعلاً، فإن استدعاء النظام يفشل مع الخطأ EAGAIN.

للاستفادة من الأقفال الإلزامية، يجب تمكين القفل الإلزامي على كل من نظام الملفات الذي يحتوي على الملف المراد قفله، وعلى الملف نفسه. يُمكن القفل الإلزامي على نظام ملفات باستخدام خيار "-o mand" للأمر mount(8)، أو علم MS_MANDLOCK لـ mount(2). يُمكن القفل الإلزامي على ملف عن طريق تعطيل إذن التنفيذ للمجموعة على الملف وتمكين بت إذن set-group-ID (انظر chmod(1) و chmod(2)).

لم يتم تحديد القفل الإلزامي بواسطة POSIX. تدعم بعض الأنظمة الأخرى أيضًا القفل الإلزامي، على الرغم من أن تفاصيل كيفية تمكينه تختلف عبر الأنظمة.

الأقفال المفقودة

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

عندما يحدد نظام الملفات أن القفل قد فُقد، قد تفشل طلبات read(2) أو write(2) المستقبلية مع الخطأ EIO. سيستمر هذا الخطأ حتى يُزال القفل أو يُغلق واصف الملف. منذ لينكس 3.12، يحدث هذا على الأقل لـ NFSv4 (بما في ذلك جميع الإصدارات الفرعية).

ترسل بعض إصدارات UNIX إشارة (SIGLOST) في هذه الحالة. لا تعرّف لينكس هذه الإشارة، ولا توفر أي إشعار غير متزامن بالأقفال المفقودة.

إدارة الإشارات

تُستخدم F_GETOWN و F_SETOWN و F_GETOWN_EX و F_SETOWN_EX و F_GETSIG و F_SETSIG لإدارة إشارات توفر الإدخال/الإخراج:

F_GETOWN (void)
إرجاع (كنتيجة للدالة) معرف العملية أو معرف مجموعة العمليات التي تتلقى حاليًا إشارات SIGIO و SIGURG للأحداث على واصف الملف fd. تُعاد معرفات العمليات كقيم موجبة؛ وتُعاد معرفات مجموعات العمليات كقيم سالبة (ولكن انظر قسم BUGS أدناه). يُتجاهل المعامل arg.
F_SETOWN (int)
ضبط معرف العملية أو معرف مجموعة العمليات التي ستتلقى إشارات SIGIO و SIGURG للأحداث على واصف الملف fd. يُحدد معرف العملية المستهدفة أو مجموعة العمليات في arg. يُحدد معرف العملية كقيمة موجبة؛ ويُحدد معرف مجموعة العمليات كقيمة سالبة. في الغالب، يحدد المستدعِي نفسه كمالك (أي يُحدد arg كنتيجة لـ getpid(2)).
بالإضافة إلى ضبط مالك واصف الملف، يجب أيضًا تمكين توليد الإشارات على واصف الملف. يتم ذلك باستخدام عملية fcntl() F_SETFL لضبط علم حالة الملف O_ASYNC على واصف الملف. لاحقًا، تُرسل إشارة SIGIO كلما أصبح الإدخال أو الإخراج ممكنًا على واصف الملف. يمكن استخدام عملية fcntl() F_SETSIG للحصول على تسليم إشارة أخرى غير SIGIO.
يخضع إرسال إشارة إلى عملية المالك (أو المجموعة) المحددة بواسطة F_SETOWN لنفس عمليات التحقق من الأذونات الموضحة في kill(2)، حيث تكون العملية المرسلة هي تلك التي تستخدم F_SETOWN (ولكن انظر قسم BUGS أدناه). إذا فشل التحقق من الإذن، فسيتم تجاهل الإشارة بصمت. ملاحظة: تسجل عملية F_SETOWN بيانات الاستيثاق الخاصة بـ المستدعِي في وقت استدعاء fcntl()، وتُستخدم بيانات الاستيثاق المحفوظة هذه للتحقق من الأذونات.
إذا كان واصف الملف fd يشير إلى مقبس، فإن F_SETOWN يختار أيضًا مستلم إشارات SIGURG التي تُسلم عند وصول بيانات خارج النطاق (out-of-band) على ذلك المقبس. (تُرسل SIGURG في أي حالة يبلغ فيها select(2) أن المقبس لديه "حالة استثنائية").
كان ما يلي صحيحًا في لينكس 2.6.x حتى لينكس 2.6.11 (بما في ذلك هذا الأخير):
إذا أُعطيت قيمة غير صفرية لـ F_SETSIG في عملية متعددة الخيوط تعمل مع مكتبة خيوط تدعم مجموعات الخيوط (مثل NPTL)، فإن القيمة الموجبة المعطاة لـ F_SETOWN لها معنى مختلف: فبدلاً من كونها معرف عملية يحدد عملية كاملة، تكون معرف خيط يحدد خيطًا معينًا داخل عملية. وبالتالي، قد يكون من الضروري تمرير نتيجة gettid(2) إلى F_SETOWN بدلاً من getpid(2) للحصول على نتائج منطقية عند استخدام F_SETSIG. (في تنفيذات خيوط لينكس الحالية، يكون معرف الخيط الرئيس هو نفسه معرف العملية الخاص به. وهذا يعني أن البرنامج أحادي الخيط يمكنه استخدام gettid(2) أو getpid(2) على حد سواء في هذا السيناريو). لاحظ، مع ذلك، أن البيانات الواردة في هذه الفقرة لا تنطبق على إشارة SIGURG المتولدة لبيانات خارج النطاق على مقبس: تُرسل هذه الإشارة دائمًا إما إلى عملية أو مجموعة عمليات، اعتمادًا على القيمة المعطاة لـ F_SETOWN.
أُسقط السلوك أعلاه عن طريق الخطأ في لينكس 2.6.12، ولن يُستعاد. بدءًا من لينكس 2.6.32 فصاعدًا، استخدم F_SETOWN_EX لتوجيه إشارات SIGIO و SIGURG إلى خيط معين.
إرجاع إعدادات مالك واصف الملف الحالية كما حددتها عملية F_SETOWN_EX سابقة. تُعاد المعلومات في البنية التي يشير إليها arg، والتي لها الشكل التالي:

struct f_owner_ex {

int type;
pid_t pid; };

سيحتوي حقل type على إحدى القيم F_OWNER_TID، أو F_OWNER_PID، أو F_OWNER_PGRP. حقل pid هو عدد صحيح موجب يمثل معرف خيط، أو معرف عملية، أو معرف مجموعة عمليات. انظر F_SETOWN_EX لمزيد من التفاصيل.
تؤدي هذه العملية مهمة مماثلة لـ F_SETOWN. وهي تسمح لـ المستدعِي بتوجيه إشارات توفر الإدخال/الإخراج إلى خيط أو عملية أو مجموعة عمليات معينة. يحدد المستدعِي هدف الإشارات عبر arg، وهو مؤشر إلى بنية f_owner_ex. يحتوي حقل type على إحدى القيم التالية، والتي تحدد كيفية تفسير pid:
إرسال الإشارة إلى الخيط الذي يكون معرفه (القيمة المعادة بواسطة استدعاء clone(2) أو gettid(2)) محددًا في pid.
إرسال الإشارة إلى العملية التي يكون معرفها محددًا في pid.
إرسال الإشارة إلى مجموعة العمليات التي يكون معرفها محددًا في pid. (لاحظ أنه، على عكس F_SETOWN، يُحدد معرف مجموعة العمليات كقيمة موجبة هنا).
إرجاع (كنتيجة للدالة) الإشارة المرسلة عندما يصبح الإدخال أو الإخراج ممكنًا. القيمة صفر تعني إرسال SIGIO. أي قيمة أخرى (بما في ذلك SIGIO) هي الإشارة المرسلة بدلاً من ذلك، وفي هذه الحالة تتوفر معلومات إضافية لمعالج الإشارة إذا ثُبت بـ SA_SIGINFO. يُتجاهل arg.
ضبط الإشارة المرسلة عندما يصبح الإدخال أو الإخراج ممكنًا على القيمة المعطاة في arg. القيمة صفر تعني إرسال إشارة SIGIO المبدئية. أي قيمة أخرى (بما في ذلك SIGIO) هي الإشارة المراد إرسالها بدلاً من ذلك، وفي هذه الحالة تتوفر معلومات إضافية لمعالج الإشارة إذا ثُبت بـ SA_SIGINFO.
باستخدام F_SETSIG مع قيمة غير صفرية، وضبط SA_SIGINFO لمعالج الإشارة (انظر sigaction(2))، تُمَرّر معلومات إضافية حول أحداث الإدخال/الإخراج إلى المعالج في بنية siginfo_t. إذا أشار حقل si_code إلى أن المصدر هو SI_SIGIO، فإن حقل si_fd يعطي واصف الملف المرتبط بالحدث. بخلاف ذلك، لا يوجد مؤشر على أي واصفات ملفات معلقة، ويجب عليك استخدام الآليات المعتادة (select(2) و poll(2) و read(2) مع ضبط O_NONBLOCK وما إلى ذلك) لتحديد واصفات الملفات المتاحة للإدخال/الإخراج.
لاحظ أن واصف الملف المتوفر في si_fd هو الذي حُدد أثناء عملية F_SETSIG. قد يؤدي هذا إلى حالة نادرة غير معتادة. إذا نُسخ واصف الملف (dup(2) أو ما شابه)، وأُغلق واصف الملف الأصلي، فستستمر أحداث الإدخال/الإخراج في التولد، ولكن حقل si_fd سيحتوي على رقم واصف الملف المغلق الآن.
باختيار إشارة زمن حقيقي (قيمة >= SIGRTMIN)، يمكن جدولة أحداث إدخال/إخراج متعددة باستخدام نفس أرقام الإشارات. (تعتمد الجدولة على الذاكرة المتاحة). تتوفر معلومات إضافية إذا ضُبطت SA_SIGINFO لمعالج الإشارة، كما هو موضح أعلاه.
لاحظ أن لينكس تفرض حدًا على عدد إشارات الزمن الحقيقي التي قد تُجدول لعملية ما (انظر getrlimit(2) و signal(7)) وإذا تم الوصول إلى هذا الحد، فإن الـ نواة تعود إلى تسليم SIGIO، وتُسلم هذه الإشارة إلى العملية بأكملها بدلاً من خيط معين.

باستخدام هذه الآليات، يمكن للبرنامج تنفيذ إدخال/إخراج غير متزامن بالكامل دون استخدام select(2) أو poll(2) في معظم الأوقات.

استخدام O_ASYNC مخصص لـ BSD ولينكس. الاستخدام الوحيد لـ F_GETOWN و F_SETOWN المحدد في POSIX.1 هو بالتزامن مع استخدام إشارة SIGURG على المقابس. (لا يحدد POSIX إشارة SIGIO). تُعد F_GETOWN_EX و F_SETOWN_EX و F_GETSIG و F_SETSIG ميزات مخصصة للينكس. لدى POSIX إدخال/إخراج غير متزامن وبنية aio_sigevent لتحقيق أشياء مماثلة؛ وهذه متوفرة أيضًا في لينكس كجزء من مكتبة جـنو سي (glibc).

الإيجارات

تُستخدم F_SETLEASE و F_GETLEASE (لينكس 2.4 فصاعدًا) لإنشاء عقد إيجار جديد، واستعادة العقد الحالي، على وصف الملف المفتوح الذي يشير إليه واصف الملف fd. يوفر عقد إيجار الملف آلية يتم من خلالها إخطار العملية التي تحمل العقد ("حائز العقد") (عبر تسليم إشارة) عندما تحاول عملية أخرى ("كاسر العقد") إجراء open(2) أو truncate(2) للملف الذي يشير إليه واصف الملف هذا.

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

ترتبط عقود الإيجار بوصف ملف مفتوح (انظر open(2)). وهذا يعني أن واصفات الملفات المكررة (التي أُنشئت بواسطة، على سبيل المثال، fork(2) أو dup(2)) تشير إلى نفس عقد الإيجار، ويمكن تعديل هذا العقد أو تحريره باستخدام أي من هذه الواصفات. علاوة على ذلك، يُحرّر عقد الإيجار إما بعملية F_UNLCK صريحة على أي من واصفات الملفات المكررة هذه، أو عندما تُغلق جميع واصفات الملفات هذه.

لا يمكن الحصول على عقود إيجار إلا على الملفات العادية. يمكن للعملية غير المتميزة الحصول على عقد إيجار فقط لملف يتطابق معرفه (المالك) مع معرف نظام ملفات العملية. يمكن للعملية التي تمتلك قدرة CAP_LEASE الحصول على عقود إيجار لملفات عشوائية.

يشير إلى نوع عقد الإيجار المرتبط بواصف الملف fd عن طريق إرجاع إما F_RDLCK أو F_WRLCK أو F_UNLCK، مما يشير على التوالي إلى عقد إيجار قراءة، أو عقد إيجار كتابة، أو عدم وجود عقد إيجار. يُتجاهل arg.

عندما تقوم عملية ("كاسر العقد") بإجراء open(2) أو truncate(2) يتعارض مع عقد إيجار أُنشئ عبر F_SETLEASE، فسيُحظر استدعاء النظام بواسطة الـ نواة وتخطر الـ نواة حائز العقد بإرسال إشارة إليه (SIGIO بشكل مبدئي). يجب على حائز العقد الاستجابة لاستلام هذه الإشارة من خلال القيام بأي تنظيف مطلوب استعدادًا للوصول إلى الملف من قبل عملية أخرى (مثل تفريغ الخبيئات) ثم إما إزالة العقد أو خفض درجته. تُزال عقود الإيجار بإجراء عملية F_SETLEASE مع تحديد arg كـ F_UNLCK. إذا كان حائز العقد يحمل حاليًا عقد إيجار كتابة على الملف، وكان كاسر العقد يفتح الملف للقراءة، فيكفي لحائز العقد خفض درجة العقد إلى عقد إيجار قراءة. يتم ذلك بإجراء عملية F_SETLEASE مع تحديد arg كـ F_RDLCK.

إذا فشل حائز العقد في خفض درجة العقد أو إزالته خلال عدد الثواني المحدد في /proc/sys/fs/lease-break-time، فإن الـ نواة تزيل العقد أو تخفض درجته قسريًا.

بمجرد بدء كسر العقد، تعيد F_GETLEASE نوع عقد الإيجار المستهدف (إما F_RDLCK أو F_UNLCK، اعتمادًا على ما سيكون متوافقًا مع كاسر العقد) حتى يقوم حائز العقد طواعية بخفض درجة العقد أو إزالته أو تقوم الـ نواة بذلك قسريًا بعد انتهاء موقت كسر العقد.

بمجرد إزالة عقد الإيجار أو خفض درجته طواعية أو قسريًا، وبافتراض أن كاسر العقد لم يلغِ حظر استدعاء النظام الخاص به، تسمح الـ نواة لاستدعاء نظام كاسر العقد بالمتابعة.

إذا قوطع استدعاء open(2) أو truncate(2) المحظور لكاسر العقد بواسطة معالج إشارة، فإن استدعاء النظام يفشل مع الخطأ EINTR، ولكن الخطوات الأخرى لا تزال تحدث كما هو موضح أعلاه. إذا قُتل كاسر العقد بواسطة إشارة أثناء حظره في open(2) أو truncate(2)، فإن الخطوات الأخرى لا تزال تحدث كما هو موضح أعلاه. إذا حدد كاسر العقد علم O_NONBLOCK عند استدعاء open(2)، فإن الاستدعاء يفشل فوريًا مع الخطأ EWOULDBLOCK، ولكن الخطوات الأخرى لا تزال تحدث كما هو موضح أعلاه.

الإشارة المبدئية المستخدمة لإشعار حامل عقد الإيجار هي SIGIO، ولكن يمكن تغيير ذلك باستخدام العملية F_SETSIG في fcntl(). إذا نُفذت عملية F_SETSIG (حتى لو حددت SIGIO)، وأُسس معالج الإشارة باستخدام SA_SIGINFO، فسيستقبل المعالج بنية siginfo_t كوسيط ثانٍ له، وسيحتوي الحقل si_fd في هذا الوسيط على واصف الملف للملف المستأجر الذي وُصل إليه بواسطة عملية أخرى. (هذا مفيد إذا كان المستدعِي يحمل عقود إيجار لملفات متعددة.)

إشعار تغيير الملفات والدلائل (dnotify)

(بدءًا من لينكس 2.4) يوفر إشعاراً عندما يتغير الدليل المشار إليه بواسطة fd أو أي من الملفات التي يحتوي عليها. تُحدد الأحداث المراد الإشعار بها في arg، وهو قناع بتات (bit mask) يُحدد عبر إجراء عملية OR لصفر أو أكثر من البتات التالية:

وُصل إلى ملف (read(2)،‏ pread(2)،‏ readv(2)، وما شابه)
عُدل ملف (write(2)،‏ pwrite(2)،‏ writev(2)،‏ truncate(2)،‏ ftruncate(2)، وما شابه).
أُنشئ ملف (open(2)،‏ creat(2)،‏ mknod(2)،‏ mkdir(2)،‏ link(2)،‏ symlink(2)،‏ rename(2) إلى هذا الدليل).
فُصل رابط ملف (unlink(2)،‏ rename(2) إلى دليل آخر، rmdir(2)).
غُير اسم ملف داخل هذا الدليل (rename(2)).
غُيرت سمات ملف (chown(2)،‏ chmod(2)،‏ utime(2)،‏ utimensat(2)، وما شابه).
(من أجل الحصول على هذه التعريفات، يجب تعريف ماكرو اختبار الميزة _GNU_SOURCE قبل تضمين أي ملفات رأسية.)
إشعارات الدليل عادةً ما تكون "طلقة واحدة" (one-shot)، ويجب على التطبيق إعادة التسجيل لاستلام مزيد من الإشعارات. بدلاً من ذلك، إذا ضُمّن DN_MULTISHOT في arg، فسيظل الإشعار سارياً حتى يُزال صراحةً.
سلسلة طلبات F_NOTIFY تراكمية، حيث تُضاف الأحداث في arg إلى المجموعة المراقبة بالفعل. لتعطيل الإشعار بجميع الأحداث، قم باستدعاء F_NOTIFY مع تحديد arg كـ 0.
يحدث الإشعار عبر تسليم إشارة. الإشارة المبدئية هي SIGIO، ولكن يمكن تغيير ذلك باستخدام العملية F_SETSIG في fcntl(). (لاحظ أن SIGIO هي إحدى الإشارات القياسية غير القابلة للجدولة؛ التحول إلى استخدام إشارة زمن حقيقي يعني إمكانية جدولة إشعارات متعددة للعملية.) في الحالة الأخيرة، يستقبل معالج الإشارة بنية siginfo_t كوسيط ثانٍ له (إذا أُسس المعالج باستخدام SA_SIGINFO) ويحتوي الحقل si_fd في هذه البنية على واصف الملف الذي ولد الإشعار (مفيد عند تأسيس إشعارات على أدلة متعددة).
خاصة عند استخدام DN_MULTISHOT، يجب استخدام إشارة زمن حقيقي للإشعار، بحيث يمكن جدولة إشعارات متعددة.
ملاحظة: يجب على التطبيقات الجديدة استخدام واجهة inotify (المتوفرة منذ لينكس 2.6.13)، والتي توفر واجهة متفوقة بكثير للحصول على إشعارات أحداث نظام الملفات. انظر inotify(7).

تغيير سعة الأنبوب

يغير سعة الأنبوب المشار إليه بواسطة fd لتكون على الأقل arg بايت. يمكن لعملية غير متميزة ضبط سعة الأنبوب لأي قيمة بين حجم صفحة النظام والحد المعرف في /proc/sys/fs/pipe-max-size (انظر proc(5)). محاولات تعيين سعة الأنبوب تحت حجم الصفحة تُقرب بصمت إلى حجم الصفحة. محاولات عملية غير متميزة لتعيين سعة الأنبوب أعلى من الحد في /proc/sys/fs/pipe-max-size تؤدي إلى الخطأ EPERM؛ يمكن لعملية متميزة (CAP_SYS_RESOURCE) تجاوز الحد.
عند تخصيص المخزن المؤقت للأنبوب، قد تستخدم النواة سعة أكبر من arg، إذا كان ذلك مناسباً للتنفيذ. (في التنفيذ الحالي، يكون التخصيص هو مضاعف حجم الصفحة التالي لقوة العدد اثنين من الحجم المطلوب.) تُعاد السعة الفعلية (بالبايت) التي عُينت كناتج للدالة.
محاولة تعيين سعة الأنبوب أصغر من مساحة المخزن المؤقت المستخدمة حالياً لتخزين البيانات تؤدي إلى الخطأ EBUSY.
لاحظ أنه بسبب طريقة توظيف صفحات مخزن الأنبوب المؤقت عند كتابة البيانات إلى الأنبوب، فإن عدد البايتات التي يمكن كتابتها قد يكون أقل من الحجم الاسمي، اعتماداً على حجم الكتابات.
يعيد (كنتيجة للدالة) سعة الأنبوب المشار إليه بواسطة fd.

ختم الملفات

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

حالياً، يمكن تطبيق أختام الملفات فقط على واصف ملف أعادته الدالة memfd_create(2) (إذا استُخدم MFD_ALLOW_SEALING). في أنظمة الملفات الأخرى، ستعيد جميع عمليات fcntl() التي تعمل على الأختام EINVAL.

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

يضيف الأختام المحددة في وسيط قناع البتات arg إلى مجموعة أختام الفهرس المشار إليه بواسطة واصف الملف fd. لا يمكن إزالة الأختام مرة أخرى. بمجرد نجاح هذا الاستدعاء، تفرض النواة الأختام فوراً. إذا كانت المجموعة الحالية من الأختام تتضمن F_SEAL_SEAL (انظر أدناه)، فسيُرفض هذا الاستدعاء مع EPERM. إضافة ختم معين مسبقاً هي عملية لا تأثير لها، في حالة عدم تعيين F_SEAL_SEAL بالفعل. لوضع ختم، يجب أن يكون واصف الملف fd قابلاً للكتابة.
يعيد (كنتيجة للدالة) المجموعة الحالية من أختام الفهرس المشار إليه بواسطة fd. إذا لم تُعين أي أختام، يُعاد 0. إذا كان الملف لا يدعم الختم، يُعاد -1 ويُضبط errno على EINVAL.

الأختام التالية متوفرة:

إذا عُين هذا الختم، فإن أي استدعاء لاحق لـ fcntl() مع F_ADD_SEALS يفشل مع الخطأ EPERM. لذلك، يمنع هذا الختم أي تعديلات على مجموعة الأختام نفسها. إذا كانت المجموعة المبدئية للأختام لملف ما تتضمن F_SEAL_SEAL، فإن هذا يؤدي فعلياً إلى جعل مجموعة الأختام ثابتة ومقفلة.
إذا عُين هذا الختم، فلا يمكن تقليص حجم الملف المعني. يؤثر هذا على open(2) مع وسم O_TRUNC وكذلك truncate(2) و ftruncate(2). تفشل هذه الاستدعاءات مع EPERM إذا حاولت تقليص الملف المعني. زيادة حجم الملف لا تزال ممكنة.
إذا عُين هذا الختم، فلا يمكن زيادة حجم الملف المعني. يؤثر هذا على write(2) وراء نهاية الملف، و truncate(2)، و ftruncate(2)، و fallocate(2). تفشل هذه الاستدعاءات مع EPERM إذا استخدمتها لزيادة حجم الملف. إذا حافظت على الحجم أو قلصته، فستظل هذه الاستدعاءات تعمل كما هو متوقع.
إذا عُين هذا الختم، فلا يمكنك تعديل محتويات الملف. لاحظ أن تقليص أو زيادة حجم الملف لا يزال ممكناً ومسموحاً به. لذلك، يُستخدم هذا الختم عادةً بالاشتراك مع أحد الأختام الأخرى. يؤثر هذا الختم على write(2) و fallocate(2) (فقط بالاشتراك مع وسم FALLOC_FL_PUNCH_HOLE). تفشل هذه الاستدعاءات مع EPERM إذا عُين هذا الختم. علاوة على ذلك، ستفشل أيضًا محاولة إنشاء تخطيطات ذاكرة (memory-mappings) مشتركة وقابلة للكتابة عبر mmap(2) مع EPERM.
تفشل العملية F_ADD_SEALS لتعيين الختم F_SEAL_WRITE مع الخطأ EBUSY إذا كان هناك أي تخطيط مشترك وقابل للكتابة. يجب إلغاء تخطيط هذه الروابط قبل أن تتمكن من إضافة هذا الختم. علاوة على ذلك، إذا كانت هناك أي عمليات دخل/خرج غير متزامنة (io_submit(2)) معلقة على الملف، فسيُتخلص من جميع الكتابات المعلقة.
تأثير هذا الختم مشابه لـ F_SEAL_WRITE، ولكن لا يزال من الممكن تعديل محتويات الملف عبر التخطيطات المشتركة القابلة للكتابة التي أُنشئت قبل تعيين الختم. ستفشل أي محاولة لإنشاء تخطيط جديد قابل للكتابة على الملف عبر mmap(2) مع الخطأ EPERM. وبالمثل، ستفشل أي محاولة للكتابة إلى الملف عبر write(2) مع الخطأ EPERM.
باستخدام هذا الختم، يمكن لعملية واحدة إنشاء مخزن ذاكرة مؤقت يمكنها الاستمرار في تعديله مع مشاركة هذا المخزن على أساس "للقراءة فقط" مع عمليات أخرى.

تلميحات قراءة/كتابة الملف

يمكن استخدام تلميحات عمر الكتابة لإبلاغ النواة بالعمر المتوقع النسبي للكتابات على فهرس معين أو عبر وصف ملف مفتوح معين. (انظر open(2) للحصول على شرح لأوصاف الملفات المفتوحة.) في هذا السياق، يعني مصطلح "عمر الكتابة" الوقت المتوقع الذي ستعيشه البيانات على الوسائط قبل أن تُستبدل أو تُمحى.

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

العمليات التالية يمكن تطبيقها على واصف الملف، fd:

يعيد قيمة تلميح القراءة/الكتابة المرتبط بالفهرس الأساسي المشار إليه بواسطة fd.
يضبط قيمة تلميح القراءة/الكتابة المرتبط بالفهرس الأساسي المشار إليه بواسطة fd. يستمر هذا التلميح حتى يُعدل صراحةً أو يُفصل نظام الملفات الأساسي.
يعيد قيمة تلميح القراءة/الكتابة المرتبط بوصف الملف المفتوح المشار إليه بواسطة fd.
يضبط قيمة تلميح القراءة/الكتابة المرتبط بوصف الملف المفتوح المشار إليه بواسطة fd.

إذا لم يُخصص تلميح قراءة/كتابة لوصف ملف مفتوح، فسيستخدم القيمة المخصصة للفهرس، إن وجدت.

تلميحات القراءة/الكتابة التالية صالحة منذ لينكس 4.13:

لم يُضبط أي تلميح محدد. هذه هي القيمة المبدئية.
لا يوجد عمر كتابة محدد مرتبط بهذا الملف أو الفهرس.
يُتوقع أن يكون للبيانات المكتوبة إلى هذا الفهرس أو عبر وصف الملف المفتوح هذا عمر قصير.
يُتوقع أن يكون للبيانات المكتوبة إلى هذا الفهرس أو عبر وصف الملف المفتوح هذا عمر أطول من البيانات المكتوبة بـ RWH_WRITE_LIFE_SHORT.
يُتوقع أن يكون للبيانات المكتوبة إلى هذا الفهرس أو عبر وصف الملف المفتوح هذا عمر أطول من البيانات المكتوبة بـ RWH_WRITE_LIFE_MEDIUM.
يُتوقع أن يكون للبيانات المكتوبة إلى هذا الفهرس أو عبر وصف الملف المفتوح هذا عمر أطول من البيانات المكتوبة بـ RWH_WRITE_LIFE_LONG.

جميع تلميحات الكتابة المحددة نسبية لبعضها البعض، ولا ينبغي عزو أي معنى مطلق فردي لها.

قيمة الإرجاع

في حالة الاستدعاء الناجح، تعتمد قيمة الإرجاع على العملية:

واصف الملف الجديد.
قيمة أوسام واصف الملف.
قيمة أوسام حالة الملف.
نوع عقد الإيجار المحتفظ به على واصف الملف.
F_GETOWN
قيمة مالك واصف الملف.
قيمة الإشارة المرسلة عندما تصبح القراءة أو الكتابة ممكنة، أو صفر لسلوك SIGIO التقليدي.
سعة الأنبوب.
قناع بتات يحدد الأختام التي عُينت للفهرس المشار إليه بواسطة fd.
جميع العمليات الأخرى
صفر.

عند الخطأ، تُعاد القيمة -1، ويُضبط errno للإشارة إلى الخطأ.

الأخطاء

العملية محظورة بسبب أقفال تحتفظ بها عمليات أخرى.
العملية محظورة لأن الملف قد خُطط في الذاكرة بواسطة عملية أخرى.
fd ليس واصف ملف مفتوح
op هو F_SETLK أو F_SETLKW ووضع فتح واصف الملف لا يتطابق مع نوع القفل المطلوب.
op هو F_SETPIPE_SZ وسعة الأنبوب الجديدة المحددة في arg أصغر من مساحة المخزن المؤقت المستخدمة حالياً لتخزين البيانات في الأنبوب.
op هو F_ADD_SEALS، و arg يتضمن F_SEAL_WRITE، وهناك تخطيط مشترك وقابل للكتابة على الملف المشار إليه بواسطة fd.
كُشف عن أن عملية F_SETLKW المحددة ستسبب طريقاً مسدوداً (deadlock).
تقع lock خارج مساحة العناوين التي يمكن الوصول إليها.
قيمة op هي F_SETLKW أو F_OFD_SETLKW وقُطعت العملية بواسطة إشارة؛ راجع signal(7).
قيمة op هي F_GETLK أو F_SETLK أو F_OFD_GETLK أو F_OFD_SETLK، وقُطعت العملية بواسطة إشارة قبل فحص القفل أو الاستحواذ عليه. يحدث هذا غالباً عند قفل ملف بعيد (مثل القفل عبر NFS)، ولكن قد يحدث محلياً أحياناً.
القيمة المحددة في op غير معروفة لهذه النواة.
قيمة op هي F_ADD_SEALS وتتضمن arg بت ختم (sealing bit) غير معروف.
قيمة op هي F_ADD_SEALS أو F_GET_SEALS ونظام الملفات الذي يحتوي على الـ inode المشار إليه بواسطة fd لا يدعم الختم (sealing).
قيمة op هي F_DUPFD و arg سالبة أو أكبر من أقصى قيمة مسموح بها (راجع مناقشة RLIMIT_NOFILE في getrlimit(2)).
قيمة op هي F_SETSIG و arg ليست رقم إشارة مسموح به.
قيمة op هي F_OFD_SETLK أو F_OFD_SETLKW أو F_OFD_GETLK، ولم تُحدد l_pid كصفر.
قيمة op هي F_DUPFD ووُصل إلى الحد الأقصى لواصفات الملفات المفتوحة لكل عملية.
فُتح عدد كبير جداً من أقفال المقاطع (segment locks)، أو جدول الأقفال ممتلئ، أو فشل بروتوكول قفل بعيد (مثل القفل عبر NFS).
حُددت F_NOTIFY في op، ولكن fd لا يشير إلى دليل.
قيمة op هي F_SETPIPE_SZ ووُصل إلى حد الأنابيب (pipe limit) المرن أو الصلب للمستخدم؛ راجع pipe(7).
حُووِل مسح علامة O_APPEND لملف عُينت له سمة الإلحاق فقط (append-only).
كانت op هي F_ADD_SEALS، ولكن fd لم يكن مفتوحاً للكتابة أو أن مجموعة الأختام الحالية على الملف تتضمن بالفعل F_SEAL_SEAL.

المعايير

POSIX.1-2008.

تعد العمليات F_GETOWN_EX و F_SETOWN_EX و F_SETPIPE_SZ و F_GETPIPE_SZ و F_GETSIG و F_SETSIG و F_NOTIFY و F_GETLEASE و F_SETLEASE خاصة بلينكس. (عرّف ماكرو _GNU_SOURCE للحصول على هذه التعريفات.)

تعد العمليات F_OFD_SETLK و F_OFD_SETLKW و F_OFD_GETLK خاصة بلينكس (ويجب تعريف _GNU_SOURCE للحصول على تعريفاتها)، ولكن يجري العمل على تضمينها في النسخة القادمة من POSIX.1.

العمليتان F_ADD_SEALS و F_GET_SEALS خاصتان بلينكس.

التاريخ

SVr4، 4.3BSD، POSIX.1-2001.

فقط العمليات F_DUPFD و F_GETFD و F_SETFD و F_GETFL و F_SETFL و F_GETLK و F_SETLK و F_SETLKW هي المحددة في POSIX.1-2001.

العمليتان F_GETOWN و F_SETOWN محددتان في POSIX.1-2001. (للحصول على تعريفاتهما، عرّف إما _XOPEN_SOURCE بقيمة 500 أو أكثر، أو _POSIX_C_SOURCE بقيمة 200809L أو أكثر.)

العملية F_DUPFD_CLOEXEC محددة في POSIX.1-2008. (للحصول على هذا التعريف، عرّف _POSIX_C_SOURCE بقيمة 200809L أو أكثر، أو _XOPEN_SOURCE بقيمة 700 أو أكثر.)

ملاحظات

تختلف الأخطاء التي ترجعها dup2(2) عن تلك التي ترجعها F_DUPFD.

قفل الملفات

لم يُصمم استدعاء النظام fcntl() الأصلي في لينكس للتعامل مع إزاحات الملفات الكبيرة (في هيكل flock). وبناءً على ذلك، أُضيف استدعاء نظام fcntl64() في لينكس 2.4. يستخدم استدعاء النظام الأحدث هيكلاً مختلفاً لقفل الملفات، flock64، والعمليات المقابلة لها F_GETLK64 و F_SETLK64 و F_SETLKW64. ومع ذلك، يمكن للتطبيقات التي تستخدم glibc تجاهل هذه التفاصيل، حيث تستخدم دالة الغلاف fcntl() استدعاء النظام الأحدث بشفافية حيثما توفر.

أقفال السجلات

منذ لينكس 2.0، لا يوجد تفاعل بين أنواع الأقفال التي يضعها flock(2) و fcntl().

تحتوي عدة أنظمة على حقول أكثر في struct flock مثل l_sysid (لتحديد الحاسوب الذي يُحتفظ فيه بالقفل). ومن الواضح أن l_pid وحده لن يكون مفيداً جداً إذا كانت العملية التي تحمل القفل تعيش على حاسوب مختلف؛ في لينكس، وعلى الرغم من وجود هذا الحقل في بعض المعماريات (مثل MIPS32)، إلا أنه لا يُستخدم.

لم يُصمم استدعاء النظام fcntl() الأصلي في لينكس للتعامل مع إزاحات الملفات الكبيرة (في هيكل flock). وبناءً على ذلك، أُضيف استدعاء نظام fcntl64() في لينكس 2.4. يستخدم استدعاء النظام الأحدث هيكلاً مختلفاً لقفل الملفات، flock64، والعمليات المقابلة لها F_GETLK64 و F_SETLK64 و F_SETLKW64. ومع ذلك، يمكن للتطبيقات التي تستخدم glibc تجاهل هذه التفاصيل، حيث تستخدم دالة الغلاف fcntl() استدعاء النظام الأحدث بشفافية حيثما توفر.

قفل السجلات و NFS

قبل لينكس 3.12، إذا فقد عميل NFSv4 الاتصال بالخادم لفترة زمنية (تُعرف بأنها أكثر من 90 ثانية دون تواصل)، فقد يفقد القفل ويستعيده دون أن يدرك ذلك أبداً. (تُعرف الفترة الزمنية التي يُفترض بعدها فقدان الاتصال باسم NFSv4 leasetime. في خادم لينكس NFS، يمكن تحديد ذلك من خلال النظر في /proc/fs/nfsd/nfsv4leasetime، الذي يعبر عن الفترة بالثواني. القيمة المبدئية لهذا الملف هي 90.) يخاطر هذا السيناريو باحتمال فساد البيانات، حيث قد تستحوذ عملية أخرى على قفل في الفترة الفاصلة وتجري عمليات إدخال/إخراج للملف.

منذ لينكس 3.12، إذا فقد عميل NFSv4 الاتصال بالخادم، فإن أي عملية إدخال/إخراج للملف بواسطة عملية "تعتقد" أنها تملك قفلاً ستفشل حتى تقوم تلك العملية بإغلاق الملف وإعادة فتحه. يمكن ضبط معامل للنواة، nfs.recover_lost_locks، على 1 للحصول على سلوك ما قبل 3.12، حيث يحاول العميل استعادة الأقفال المفقودة عند إعادة الاتصال بالخادم. وبسبب خطر فساد البيانات المصاحب لذلك، فإن هذا المعامل يكون 0 (معطل) بشكل مبدئي.

العلل

F_SETFL

من غير الممكن استخدام F_SETFL لتغيير حالة العلامتين O_DSYNC و O_SYNC. وتُتجاهل محاولات تغيير حالة هاتين العلامتين بصمت.

F_GETOWN

يعني وجود قيد في اتفاقيات استدعاء نظام لينكس في بعض المعماريات (لا سيما i386) أنه إذا وقع معرف مجموعة عمليات (سالب) مطلوب إرجاعه بواسطة F_GETOWN في النطاق من -1 إلى -4095، فإن glibc يفسر قيمة الإرجاع خطأً على أنها خطأ في استدعاء النظام؛ أي أن قيمة إرجاع fcntl() ستكون -1، وسوف يحتوي errno على معرف مجموعة العمليات (الموجب). تتجنب عملية F_GETOWN_EX الخاصة بلينكس هذه المشكلة. منذ glibc 2.11، جعل glibc مشكلة F_GETOWN في النواة غير مرئية من خلال تنفيذ F_GETOWN باستخدام F_GETOWN_EX.

F_SETOWN

في لينكس 2.4 وما قبله، توجد علة يمكن أن تحدث عندما تستخدم عملية غير مميزة F_SETOWN لتحديد مالك واصف ملف مقبس كعملية (أو مجموعة عمليات) غير المستدعِي. في هذه الحالة، يمكن أن يرجع fcntl() القيمة -1 مع ضبط errno على EPERM، حتى عندما تكون العملية المالك (أو المجموعة) هي عملية يملك المستدعِي إذناً بإرسال إشارات إليها. وبالرغم من إرجاع هذا الخطأ، يُضبط مالك واصف الملف، وتُرسل الإشارات إلى المالك.

كشف الانغلاق التام (Deadlock)

قد تعطي خوارزمية كشف الانغلاق التام التي تستخدمها النواة عند التعامل مع طلبات F_SETLKW نتائج سلبية خاطئة (الفشل في كشف الانغلاقات، مما يترك مجموعة من العمليات المنغلقة محجوبة إلى الأبد) وإيجابية خاطئة (أخطاء EDEADLK عند عدم وجود انغلاق). على سبيل المثال، تحد النواة من عمق البحث عن التبعية للقفل إلى 10 خطوات، مما يعني أن سلاسل الانغلاق الدائرية التي تتجاوز هذا الحجم لن تُكشف. بالإضافة إلى ذلك، قد تشير النواة خطأً إلى وجود انغلاق عندما تضع عمليتان أو أكثر (أُنشئت باستخدام العلامة CLONE_FILES في clone(2)) أقفالاً تبدو للنواة متعارضة.

القفل الإلزامي

يخضع تنفيذ لينكس للقفل الإلزامي لظروف التسابق (race conditions) التي تجعله غير موثوق: فقد يعدل استدعاء write(2) يتداخل مع قفل البيانات بعد الاستحواذ على القفل الإلزامي؛ وقد يكتشف استدعاء read(2) يتداخل مع قفل تغييرات في البيانات أُجريت فقط بعد الاستحواذ على قفل كتابة. وتوجد تسابُقات مماثلة بين الأقفال الإلزامية و mmap(2). لذا يُنصح بعدم الاعتماد على القفل الإلزامي.

انظر أيضًا

dup2(2), flock(2), open(2), socket(2), lockf(3), capabilities(7), feature_test_macros(7), lslocks(8)

الملفات locks.txt و mandatory-locking.txt و dnotify.txt في دليل مصدر نواة لينكس Documentation/filesystems/ (في النواة الأقدم، تكون هذه الملفات مباشرة تحت الدليل Documentation/، ويُسمى mandatory-locking.txt باسم mandatory.txt)

ترجمة

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

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

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

2 مايو 2024 صفحات دليل لينكس 6.9.1