Điều gì xảy ra khi một tệp được phân trang 100% vào bộ đệm trang bị sửa đổi bởi một quy trình khác


14

Tôi biết rằng khi một trang bộ đệm trang được sửa đổi, nó bị đánh dấu bẩn và yêu cầu phải viết lại, nhưng điều gì xảy ra khi:

Kịch bản: Tệp / ứng dụng / EXE, là tệp thực thi, được phân trang hoàn toàn vào bộ đệm của trang (tất cả các trang của nó nằm trong bộ đệm / bộ nhớ) và được thực hiện theo quy trình P

Phát hành liên tục sau đó thay thế / ứng dụng / EXE bằng một tệp thực thi hoàn toàn mới.

Giả định 1: Tôi giả sử rằng quy trình P (và bất kỳ ai khác có bộ mô tả tệp tham chiếu tệp thực thi cũ) sẽ tiếp tục sử dụng bộ nhớ / ứng dụng / EXE cũ mà không gặp sự cố và bất kỳ quy trình mới nào cố gắng thực hiện đường dẫn đó sẽ nhận được thực thi mới.

Giả định 2: Tôi giả sử rằng nếu không phải tất cả các trang của tệp được ánh xạ vào bộ nhớ, mọi thứ sẽ ổn cho đến khi có lỗi trang yêu cầu các trang từ tệp đã được thay thế và có thể xảy ra lỗi segfault?

Câu hỏi 1: Nếu bạn khóa tất cả các trang của tệp với một cái gì đó như vmtouch, điều đó có làm thay đổi kịch bản không?

Câu hỏi 2: Nếu / apps / EXE nằm trên NFS từ xa, điều đó có tạo ra sự khác biệt nào không? (Tôi cho là không)

Vui lòng sửa hoặc xác nhận 2 giả định của tôi và trả lời 2 câu hỏi của tôi.

Giả sử đây là hộp CentOS 7.6 với một số loại hạt nhân 3.10.0-957.el7

Cập nhật: Suy nghĩ thêm về nó, tôi tự hỏi liệu kịch bản này không khác gì bất kỳ kịch bản trang bẩn nào khác ..

Tôi cho rằng quá trình viết nhị phân mới sẽ thực hiện đọc và nhận tất cả các trang bộ đệm vì tất cả đều được phân trang và sau đó tất cả các trang đó sẽ bị đánh dấu bẩn. Nếu chúng bị khóa, chúng sẽ chỉ là những trang vô dụng chiếm bộ nhớ cốt lõi sau khi số lượng ref giảm về không.

Tôi nghi ngờ khi các chương trình hiện đang kết thúc, mọi thứ khác sẽ sử dụng nhị phân mới. Giả sử tất cả đều đúng, tôi đoán nó chỉ thú vị khi chỉ một số tệp được phân trang.


Chỉ cần làm cho nó trở nên rõ ràng, việc thay thế một tệp sẽ không phải là một vấn đề lớn (tùy thuộc vào việc nó được mở lại bởi ứng dụng và cách ứng dụng phản ứng với nội dung đã sửa đổi), nhưng sửa đổi các tệp bị lỗi có thể làm hỏng ứng dụng (đây là một vấn đề phổ biến trong thế giới java khi một tệp zip có mục nhập thư mục được thay đổi). Tuy nhiên, điều này phụ thuộc vào nền tảng, không đảm bảo rằng các khu vực được xem có thay đổi hay không.
eckes

Câu trả lời:


12

Phát hành liên tục sau đó thay thế / ứng dụng / EXE bằng một tệp thực thi hoàn toàn mới.

Đây là một phần quan trọng.

Cách một tệp mới được phát hành là bằng cách tạo một tệp mới (ví dụ /apps/EXE.tmp.20190907080000), viết nội dung, đặt quyền và quyền sở hữu và cuối cùng đổi tên (2) thành tên cuối cùng /apps/EXE, thay thế tệp cũ.

Kết quả là tệp mới có số inode mới (có nghĩa là, thực tế, đó là một tệp khác.)

Và tệp cũ có số inode riêng, thực tế vẫn còn xung quanh mặc dù tên tệp không còn trỏ đến nó nữa (hoặc không có tên tệp nào trỏ đến inode đó nữa).

Vì vậy, mấu chốt ở đây là khi chúng ta nói về "tệp" trong Linux, chúng ta thường thực sự nói về "inodes" kể từ khi tệp được mở, inode là tài liệu tham khảo chúng ta lưu giữ tệp.

Giả định 1 : Tôi giả sử rằng quy trình P (và bất kỳ ai khác có bộ mô tả tệp tham chiếu tệp thực thi cũ) sẽ tiếp tục sử dụng bộ nhớ / ứng dụng / EXE cũ mà không gặp sự cố và bất kỳ quy trình mới nào cố gắng thực hiện đường dẫn đó sẽ nhận được thực thi mới.

Chính xác.

Giả định 2 : Tôi giả sử rằng nếu không phải tất cả các trang của tệp được ánh xạ vào bộ nhớ, mọi thứ sẽ ổn cho đến khi có lỗi trang yêu cầu các trang từ tệp đã được thay thế và có thể xảy ra lỗi segfault?

Sai. Inode cũ vẫn còn, vì vậy các lỗi trang từ quá trình sử dụng nhị phân cũ vẫn có thể tìm thấy các trang đó trên đĩa.

Bạn có thể thấy một số hiệu ứng của điều này bằng cách nhìn vào /proc/${pid}/exesymlink (hoặc, tương đương, lsofđầu ra) cho quá trình chạy nhị phân cũ, sẽ hiển thị /app/EXE (deleted)để cho biết tên không còn ở đó nhưng inode vẫn ở xung quanh.

Bạn cũng có thể thấy rằng không gian đĩa được sử dụng bởi nhị phân sẽ chỉ được giải phóng sau khi quá trình chết (giả sử đó là quá trình duy nhất với chế độ inode đó mở.) Kiểm tra đầu ra của dftrước và sau khi giết tiến trình, bạn sẽ thấy nó giảm theo kích thước của nhị phân cũ mà bạn nghĩ không còn nữa.

BTW, điều này không chỉ với nhị phân, mà với bất kỳ tệp đang mở nào. Nếu bạn mở một tệp trong một quy trình và xóa tệp đó, tệp sẽ được lưu trên đĩa cho đến khi quá trình đó đóng tệp (hoặc chết.) Tương tự như cách các liên kết cứng giữ một bộ đếm có bao nhiêu tên trỏ vào một nút trong đĩa, trình điều khiển hệ thống tập tin (trong nhân Linux) sẽ kiểm tra xem có bao nhiêu tài liệu tham khảo tồn tại trong nút đó trong bộ nhớ và sẽ chỉ giải phóng inode khỏi đĩa một khi tất cả các tham chiếu từ hệ thống đang chạy cũng được phát hành.

Câu hỏi 1 : Nếu bạn khóa tất cả các trang của tệp với một cái gì đó như vmtouch, điều đó sẽ thay đổi kịch bản

Câu hỏi này dựa trên giả định 2 không chính xác rằng việc không khóa các trang sẽ gây ra lỗi. Nó sẽ không.

Câu hỏi 2 : Nếu / apps / EXE nằm trên NFS từ xa, điều đó có tạo ra sự khác biệt nào không? (Tôi cho là không)

có nghĩa là hoạt động theo cùng một cách và hầu hết thời gian, nhưng có một số "vấn đề" với NFS.

Đôi khi bạn có thể thấy các thành phần của việc xóa một tệp vẫn đang mở trong NFS (hiển thị dưới dạng một tệp ẩn trong thư mục đó.)

Bạn cũng có một số cách để gán số thiết bị cho xuất NFS, để đảm bảo những số đó sẽ không bị "xáo trộn" khi máy chủ NFS khởi động lại.

Nhưng ý chính là như vậy. Trình điều khiển máy khách NFS vẫn sử dụng các nút và sẽ cố gắng giữ các tệp xung quanh (trên máy chủ) trong khi nút vẫn được tham chiếu.


1
Có đổi tên (2) cho đến khi số ref của tệp oldname không về không?
Gregg Leventhal

2
Không, đổi tên (2) sẽ không chặn. Các inode cũ được giữ xung quanh trong một thời gian rất dài.
filbranden

1
Xem câu trả lời của @ mosvy về lý do tại sao bạn không thể ghi vào tệp đang được thực thi (bạn nhận được ETXTBSY). Hủy liên kết và tạo mới có cùng tác dụng đổi tên: bạn kết thúc với một nút mới. (Đổi tên là tốt hơn vì sau đó không có thời điểm mà tên tệp không tồn tại, đó là một hoạt động nguyên tử thay thế tên để trỏ đến nút mới.)
filbranden

4
@GreggLeventhal: "Bạn đang giả định gì về quá trình phát hành liên tục mà tôi đang sử dụng khiến bạn chắc chắn nó sử dụng các tệp tạm thời?" - Bởi vì miễn là Unix tồn tại, đó là và là cách duy nhất để làm điều đó. renamelà khá nhiều tập tin và hệ thống tập tin chỉ hoạt động mà là đảm bảo được nguyên tử (giả sử chúng ta không qua hệ thống tập tin hoặc thiết bị ranh giới), vì vậy "tạo tập tin tạm thời và sau đó rename" được các mô hình tiêu chuẩn để cập nhật tập tin. Đó cũng là thứ mà mọi trình soạn thảo văn bản trên Unix sử dụng, chẳng hạn.
Jörg W Mittag

1
@ grahamj42: renamelà một phần của POSIX. Cấp, nó được bao gồm bởi tham chiếu đến ISO C (phần 7.21.4.2 trong dự thảo hiện tại), nhưng nó nằm trong đó.
Jörg W Mittag

6

Giả định 2: Tôi giả sử rằng nếu không phải tất cả các trang của tệp được ánh xạ vào bộ nhớ, mọi thứ sẽ ổn cho đến khi có lỗi trang yêu cầu các trang từ tệp đã được thay thế và có thể xảy ra lỗi segfault?

Không, điều đó sẽ không xảy ra, vì kernel sẽ không cho phép bạn mở để viết thay thế bất cứ thứ gì trong tệp đang được thực thi. Một hành động như vậy sẽ thất bại với ETXTBSY[1]:

cp /bin/sleep sleep; ./sleep 3600 & echo none > ./sleep
[9] 5332
bash: ./sleep: Text file busy

Khi dpkg, vv cập nhật tệp nhị phân, nó không ghi đè lên nó, nhưng sử dụng rename(2)chỉ đơn giản là trỏ mục nhập thư mục vào một tệp hoàn toàn khác và bất kỳ quy trình nào vẫn có ánh xạ hoặc xử lý mở đối với tệp cũ sẽ tiếp tục sử dụng mà không gặp sự cố .

[1] bảo vệ như vậy không được mở rộng cho các tệp khác mà cũng có thể được coi là "văn bản" (mã trực tiếp / thực thi): thư viện dùng chung, các lớp java, v.v; Sửa đổi một tập tin như vậy trong khi được ánh xạ bởi một quá trình khác sẽ khiến nó bị sập. Trên linux, trình liên kết động mạnh mẽ chuyển MAP_DENYWRITEcờ đến mmap(2), nhưng không có lỗi - nó không có tác dụng gì.


1
Trong kịch bản dpkg, tại thời điểm nào thì việc đổi tên hoàn thành sao cho các ứng dụng cho / apps / EXE sẽ tham chiếu đến nút của nhị phân mới? Khi không có nhiều tài liệu tham khảo cho cái cũ? Làm thế nào mà làm việc?
Gregg Leventhal

2
rename(2)là nguyên tử; Ngay sau khi hoàn thành, mục nhập dir đề cập đến tệp mới. Các quy trình vẫn đang sử dụng tệp cũ tại thời điểm đó sẽ chỉ có thể truy cập tệp đó thông qua ánh xạ hiện có hoặc thông qua các thẻ điều khiển mở đối với tệp này (có thể tham chiếu một nha sĩ mồ côi, không còn có thể truy cập được ngoài thông qua /proc/PID/fd).
mosvy

1
Tôi thích câu trả lời của bạn tốt nhất vì đề cập đến ETXTBSY của bạn đã dẫn tôi đến utcc.utoronto.ca/~cks/space/blog/unix/WhyTextFileBusyError trả lời tất cả các câu hỏi của tôi.
Gregg Leventhal

4

Câu trả lời của filbranden là đúng khi giả sử quy trình phát hành liên tục thực hiện thay thế nguyên tử đúng cách các tệp thông qua rename. Nếu không, nhưng sửa đổi tệp tại chỗ, mọi thứ sẽ khác. Tuy nhiên mô hình tinh thần của bạn vẫn bị nhầm lẫn.

Không có khả năng mọi thứ bị sửa đổi trên đĩa và không phù hợp với bộ đệm trang, bởi vì bộ đệm trang là phiên bản chính tắcphiên bản được sửa đổi. Bất kỳ ghi vào một tập tin diễn ra thông qua bộ đệm trang. Nếu nó đã có ở đó, các trang hiện có được sửa đổi. Nếu nó chưa xuất hiện, các nỗ lực sửa đổi một phần trang sẽ khiến toàn bộ trang được lưu vào bộ đệm, theo sau là sửa đổi như thể nó đã được lưu vào bộ nhớ cache. Các bài viết trải dài trên toàn bộ một trang hoặc nhiều hơn có thể (và gần như chắc chắn) tối ưu hóa bước đọc phân trang chúng. Trong mọi trường hợp, chỉ có một phiên bản có thể sửa đổi chính tắc của một tệp tồn tại (*), một trong bộ đệm của trang .

(*) Tôi hơi nói dối. Đối với NFS và các hệ thống tệp từ xa khác, có thể có nhiều hơn một và chúng thường (tùy thuộc vào tùy chọn nào và tùy chọn gắn kết và phía máy chủ được sử dụng) không thực hiện chính xác nguyên tử và sắp xếp ngữ nghĩa để ghi. Đó là lý do tại sao nhiều người trong chúng ta coi chúng bị hỏng cơ bản và từ chối sử dụng chúng cho các tình huống sẽ được viết đồng thời với việc sử dụng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.