Tôi đang triển khai hệ thống tệp FUSE nhằm cung cấp quyền truy cập thông qua các cuộc gọi POSIX quen thuộc vào các tệp thực sự được lưu trữ phía sau API RESTful. Hệ thống tập tin lưu trữ các tập tin một khi chúng đã được truy xuất lần đầu tiên để chúng dễ dàng hơn trong các lần truy cập tiếp theo.Nếu hoạt động của FUSE getattr luôn luôn được tuần tự hóa?
Tôi đang chạy hệ thống tệp ở chế độ đa luồng (mặc định là FUSE) nhưng nhận thấy các cuộc gọi getattr dường như được tuần tự hóa, mặc dù các cuộc gọi khác có thể diễn ra song song.
Khi mở tệp FUSE luôn gọi getattr trước và ứng dụng tôi hỗ trợ cần kích thước tệp được trả về bởi lệnh gọi ban đầu này là chính xác (tôi không có quyền kiểm soát hành vi này). Điều này có nghĩa là nếu tôi không có tệp được lưu trữ, tôi cần thực sự nhận được thông tin qua các lệnh gọi RESTful API. Đôi khi các cuộc gọi này xảy ra trên mạng có độ trễ cao, với thời gian chuyến đi khứ hồi khoảng 600 mili giây.
Do tính chất tuần tự rõ ràng của cuộc gọi getattr, bất kỳ quyền truy cập nào vào tệp hiện không được lưu trữ sẽ khiến toàn bộ hệ thống tệp chặn bất kỳ thao tác mới nào trong khi getattr này được bảo trì.
Tôi đã đưa ra một số cách để làm việc vòng này, nhưng tất cả dường như xấu xí hoặc dài gió, thực sự tôi chỉ muốn các cuộc gọi getattr chạy song song giống như tất cả các cuộc gọi khác dường như.
Nhìn vào mã nguồn tôi không thấy tại sao getattr nên hoạt động như thế này, FUSE khóa khóa tree_lock mutex, nhưng chỉ để đọc, và không có ghi nào xảy ra cùng một lúc.
Vì lợi ích của việc đăng nội dung đơn giản trong câu hỏi này, tôi đã thực hiện một triển khai cơ bản cực kỳ chỉ hỗ trợ getattr và cho phép trình diễn dễ dàng vấn đề.
#ifndef FUSE_USE_VERSION
#define FUSE_USE_VERSION 22
#endif
#include <fuse.h>
#include <iostream>
static int GetAttr(const char *path, struct stat *stbuf)
{
std::cout << "Before: " << path << std::endl;
sleep(5);
std::cout << "After: " << path << std::endl;
return -1;
}
static struct fuse_operations ops;
int main(int argc, char *argv[])
{
ops.getattr = GetAttr;
return fuse_main(argc, argv, &ops);
}
Sử dụng một vài thiết bị đầu cuối để gọi ls trên một con đường ở (khoảng) đồng thời cho thấy các cuộc gọi getattr thứ hai chỉ bắt đầu lần đầu tiên đã kết thúc, điều này gây ra ls thứ hai để mất ~ 10 giây thay vì của 5.
ga 1
$ date; sudo ls /mnt/cachefs/file1.ext; date
Tue Aug 27 16:56:34 BST 2013
ls: /mnt/cachefs/file1.ext: Operation not permitted
Tue Aug 27 16:56:39 BST 2013
ga 2
$ date; sudo ls /mnt/cachefs/file2.ext; date
Tue Aug 27 16:56:35 BST 2013
ls: /mnt/cachefs/file2.ext: Operation not permitted
Tue Aug 27 16:56:44 BST 2013
Như bạn có thể thấy, chênh lệch thời gian từ hai kết quả đầu ra date
từ trước ls
chỉ khác một giây, nhưng hai từ sau ls
khác 5 giây, tương ứng với độ trễ trong hàm GetAttr
. Điều này cho thấy cuộc gọi thứ hai bị chặn ở đâu đó sâu trong FUSE.
Output
$ sudo ./cachefs /mnt/cachefs -f -d
unique: 1, opcode: INIT (26), nodeid: 0, insize: 56
INIT: 7.10
flags=0x0000000b
max_readahead=0x00020000
INIT: 7.8
flags=0x00000000
max_readahead=0x00020000
max_write=0x00020000
unique: 1, error: 0 (Success), outsize: 40
unique: 2, opcode: LOOKUP (1), nodeid: 1, insize: 50
LOOKUP /file1.ext
Before: /file1.ext
After: /file1.ext
unique: 2, error: -1 (Operation not permitted), outsize: 16
unique: 3, opcode: LOOKUP (1), nodeid: 1, insize: 50
LOOKUP /file2.ext
Before: /file2.ext
After: /file2.ext
unique: 3, error: -1 (Operation not permitted), outsize: 16
Mã và các ví dụ trên là không có gì giống như ứng dụng thực tế hoặc làm thế nào ứng dụng được sử dụng, nhưng thể hiện hành vi tương tự. Tôi đã không hiển thị điều này trong ví dụ trên, nhưng tôi đã thấy rằng khi cuộc gọi getattr hoàn tất, các cuộc gọi mở tiếp theo có thể chạy song song, như tôi đã mong đợi.
Tôi đã xóa tài liệu để thử và giải thích hành vi này và cố tìm người khác báo cáo trải nghiệm tương tự nhưng dường như không tìm thấy bất kỳ điều gì.Có thể bởi vì hầu hết các triển khai của getattr sẽ nhanh đến mức bạn sẽ không chú ý hoặc quan tâm nếu nó được sắp xếp theo thứ tự, hoặc có thể bởi vì tôi đang làm điều gì đó ngớ ngẩn trong cấu hình. Tôi đang sử dụng phiên bản 2.7.4 của FUSE, vì vậy có thể đây là lỗi cũ đã được khắc phục.
Nếu có ai có bất kỳ thông tin chi tiết nào về điều này, nó sẽ được đánh giá cao!
Câu hỏi rất hay, tôi cũng quan tâm. Có thể bạn cũng nên đăng nó lên Danh sách gửi thư của nhà phát triển FUSE. – rralf
Xin lỗi rralf, tôi chỉ thấy điều này. Tôi đã đăng trên danh sách gửi thư và nhận được phản hồi gần đây, tôi sẽ sớm cập nhật câu hỏi này. – abulford