Vietnamese (machine translation)

Lưu ý

Mục đích của file này là để độc giả tiếng Việt có thể đọc và hiểu tài liệu nhân kernel dễ dàng hơn, không phải để tạo ra một nhánh tài liệu riêng. Nếu bạn có bất kỳ nhận xét hoặc cập nhật nào cho file này, vui lòng thử cập nhật file tiếng Anh gốc trước. Nếu bạn thấy có sự khác biệt giữa bản dịch và bản gốc, hoặc có vấn đề về bản dịch, vui lòng gửi góp ý hoặc patch cho người dịch của file này, hoặc nhờ người bảo trì và người review tài liệu tiếng Việt giúp đỡ.

Bản gốc:

Reference-count design for elements of lists/arrays protected by RCU

Người dịch:

Google Translate (machine translation)

Phiên bản gốc:

8541d8f725c6

Cảnh báo

Tài liệu này được dịch tự động bằng máy và chưa được review bởi người dịch. Nội dung có thể không chính xác hoặc khó hiểu ở một số chỗ. Khi có sự khác biệt với bản gốc, bản gốc luôn là chuẩn. Bản dịch chất lượng cao (được review) được đặt trong thư mục vi_VN/.

Thiết kế đếm tham chiếu cho các thành phần của danh sách/mảng được bảo vệ bởi RCU

Xin lưu ý rằng tính năng percpu-ref có thể là tính năng đầu tiên của bạn dừng lại nếu bạn cần kết hợp số lượng tham chiếu và RCU. Xin vui lòng xem include/linux/percpu-refcount.h để biết thêm thông tin. Tuy nhiên, trong những trường hợp bất thường trong đó percpu-ref sẽ tiêu tốn quá nhiều bộ nhớ, xin vui lòng đọc tiếp.


Việc đếm tham chiếu trên các thành phần của danh sách được bảo vệ theo cách truyền thống spinlocks hoặc semaphores của trình đọc/ghi rất đơn giản:

CODE LISTING MỘT:

    1. thêm() tìm kiếm_and_reference() { {

      alloc_object read_lock(&list_lock); ... search_for_element

Atomic_set(&el->rc, 1); Atomic_inc(&el->rc);

write_lock(&list_lock); ... add_element read_unlock(&list_lock); ... ...

write_unlock(&list_lock); }

}

    1. Release_referenced() xóa() { {

      ... write_lock(&list_lock);

if(atomic_dec_and_test(&el->rc)) ...

kfree(el);

... remove_element

} write_unlock(&list_lock);

... if (atomic_dec_and_test(&el->rc))

kfree(el);

...

}

Nếu danh sách/mảng này được khóa miễn phí bằng cách sử dụng RCU như khi thay đổi write_lock() trong add()delete() thành spin_lock() và thay đổi read_lock() trong search_and_reference() tới rcu_read_lock(), Atomic_inc() trong search_and_reference() có khả năng chứa tham chiếu đến một phần tử đã bị xóa khỏi danh sách/mảng. Sử dụng Atomic_inc_not_zero() trong tình huống này như sau:

CODE LISTING B:

    1. thêm() tìm kiếm_and_reference() { {

      alloc_object rcu_read_lock(); ... search_for_element

Atomic_set(&el->rc, 1); if (!atomic_inc_not_zero(&el->rc)) {
spin_lock(&list_lock); rcu_read_unlock();

trả lại FAIL;

add_element } ... ...

spin_unlock(&list_lock); rcu_read_unlock();

} } 3. 4. Release_referenced() xóa() { {

... spin_lock(&list_lock);

nếu (atomic_dec_and_test(&el->rc)) ...

call_rcu(&el->head, el_free); xóa_element

... spin_unlock(&list_lock);

} ...
if (atomic_dec_and_test(&el->rc))

call_rcu(&el->head, el_free);

...

}

Đôi khi, cần phải có một tham chiếu đến phần tử trong luồng cập nhật (ghi). Trong những trường hợp như vậy, Atomic_inc_not_zero() có thể là quá mức cần thiết vì chúng tôi giữ spinlock bên cập nhật. Thay vào đó người ta có thể sử dụng Atomic_inc() trong những trường hợp như vậy.

Không phải lúc nào cũng thuận tiện khi xử lý “FAIL” trong đường dẫn mã search_and_reference(). Trong những trường hợp như vậy, Atomic_dec_and_test() có thể được chuyển từ delete() sang el_free() như sau:

CODE LISTING C:

    1. thêm() tìm kiếm_and_reference() { {

      alloc_object rcu_read_lock(); ... search_for_element

Atomic_set(&el->rc, 1); Atomic_inc(&el->rc);

spin_lock(&list_lock); ...

add_element rcu_read_unlock();

... }

spin_unlock(&list_lock); 4.

} xóa() 3. { Release_referenced() spin_lock(&list_lock); { ...

... remove_element

if (atomic_dec_and_test(&el->rc)) spin_unlock(&list_lock);

kfree(el); ...

... call_rcu(&el->head, el_free);

} ... 5. } void el_free(struct rcu_head *rhp) {

phát hành_referenced();

}

Điểm mấu chốt là tham chiếu ban đầu được thêm bởi add() không bị xóa cho đến khi thời gian gia hạn đã trôi qua sau khi xóa. Điều này có nghĩa là search_and_reference() không thể tìm thấy phần tử này, điều đó có nghĩa là giá trị của el->rc không thể tăng. Vì vậy, một khi nó đạt tới số 0 thì không có độc giả có thể hoặc sẽ có thể tham chiếu phần tử đó. các do đó phần tử có thể được giải phóng một cách an toàn. Điều này lại đảm bảo rằng nếu bất kỳ người đọc nào tìm thấy phần tử đó, người đọc đó có thể lấy được tham chiếu một cách an toàn mà không kiểm tra giá trị của bộ đếm tham chiếu.

Ưu điểm rõ ràng của mẫu dựa trên RCU trong việc liệt kê C so với mẫu trong danh sách B là bất kỳ lệnh gọi tới search_and_reference() nào định vị một đối tượng nhất định sẽ thành công trong việc lấy được một tham chiếu đến đối tượng đó, thậm chí còn đưa ra lệnh gọi đồng thời delete() cho cùng một đối tượng. Tương tự, lợi thế rõ ràng của cả danh sách B và C so với danh sách A là lệnh gọi delete() không bị trì hoãn ngay cả khi có lệnh tùy ý số lượng lớn các cuộc gọi tới search_and_reference() để tìm kiếm điều tương tự đối tượng xóa() đã được gọi. Thay vào đó, tất cả những gì bị trì hoãn là lệnh gọi cuối cùng của kfree(), thường không phải là vấn đề trên hệ thống máy tính hiện đại, ngay cả những máy tính nhỏ.

Trong trường hợp delete() có thể ngủ, sync_rcu() có thể được gọi từ delete(), do đó el_free() có thể được gộp thành delete như sau:

  1. xóa() {

    spin_lock(&list_lock); ...

xóa_element

spin_unlock(&list_lock); ...

đồng bộ hóa_rcu();
if (atomic_dec_and_test(&el->rc))

kfree(el);

...

}

Như các ví dụ bổ sung trong kernel, mẫu trong danh sách C được sử dụng bởi việc đếm tham chiếu của struct pid, trong khi mẫu trong danh sách B được sử dụng bởi cấu trúc posix_acl.