diff --git a/fs/hmdfs/comm/device_node.c b/fs/hmdfs/comm/device_node.c index 59016ecaf931157fdf6902da878860fb18a9f271..f4155848e33c27e49d34e2b970fee2f040773376 100644 --- a/fs/hmdfs/comm/device_node.c +++ b/fs/hmdfs/comm/device_node.c @@ -1332,6 +1332,7 @@ HMDFS_CMD_ATTR(rename, F_RENAME); HMDFS_CMD_ATTR(setattr, F_SETATTR); HMDFS_CMD_ATTR(statfs, F_STATFS); HMDFS_CMD_ATTR(drop_push, F_DROP_PUSH); +HMDFS_CMD_ATTR(drop_page_push, F_DROP_PAGE_PUSH); HMDFS_CMD_ATTR(getattr, F_GETATTR); HMDFS_CMD_ATTR(fsync, F_FSYNC); HMDFS_CMD_ATTR(syncfs, F_SYNCFS); @@ -1351,6 +1352,7 @@ static struct attribute *sbi_timeout_attrs[] = { ATTR_LIST(getattr), ATTR_LIST(fsync), ATTR_LIST(syncfs), ATTR_LIST(getxattr), ATTR_LIST(setxattr), ATTR_LIST(listxattr), + ATTR_LIST(drop_page_push), NULL }; diff --git a/fs/hmdfs/comm/message_verify.c b/fs/hmdfs/comm/message_verify.c index 4c593390778c07917e9793e3f0d786efa2041566..19514a8cf0eef01335c29f8e6d88c6f0f434abd3 100644 --- a/fs/hmdfs/comm/message_verify.c +++ b/fs/hmdfs/comm/message_verify.c @@ -27,6 +27,7 @@ void hmdfs_message_verify_init(void) need_response[F_RELEASE] = false; need_response[F_CONNECT_REKEY] = false; need_response[F_DROP_PUSH] = false; + need_response[F_DROP_PAGE_PUSH] = false; for (flag = 0; flag < C_FLAG_SIZE; flag++) { for (cmd = 0; cmd < F_SIZE; cmd++) { @@ -43,11 +44,12 @@ void hmdfs_message_verify_init(void) sizeof(struct open_request) + PATH_MAX + 1; message_length[C_REQUEST][F_OPEN][HMDFS_MESSAGE_LEN_JUDGE_INDEX] = MESSAGE_LEN_JUDGE_RANGE; - message_length[C_RESPONSE][F_OPEN][HMDFS_MESSAGE_MIN_INDEX] = 0; + message_length[C_RESPONSE][F_OPEN][HMDFS_MESSAGE_MIN_INDEX] = sizeof( + struct open_response) - HMDFS_PAGE_SIZE - 1; message_length[C_RESPONSE][F_OPEN][HMDFS_MESSAGE_MAX_INDEX] = sizeof(struct open_response); message_length[C_RESPONSE][F_OPEN][HMDFS_MESSAGE_LEN_JUDGE_INDEX] = - MESSAGE_LEN_JUDGE_BIN; + MESSAGE_LEN_JUDGE_RANGE; message_length[C_REQUEST][F_ATOMIC_OPEN][HMDFS_MESSAGE_MIN_INDEX] = sizeof(struct atomic_open_request); @@ -269,6 +271,13 @@ void hmdfs_message_verify_init(void) sizeof(struct drop_push_request) + PATH_MAX + 1; message_length[C_REQUEST][F_DROP_PUSH][HMDFS_MESSAGE_LEN_JUDGE_INDEX] = MESSAGE_LEN_JUDGE_RANGE; + + message_length[C_REQUEST][F_DROP_PAGE_PUSH][HMDFS_MESSAGE_MIN_INDEX] = + sizeof(struct drop_page_push_request); + message_length[C_REQUEST][F_DROP_PAGE_PUSH][HMDFS_MESSAGE_MAX_INDEX] = + sizeof(struct drop_page_push_request) + PATH_MAX + 1; + message_length[C_REQUEST][F_DROP_PAGE_PUSH][HMDFS_MESSAGE_LEN_JUDGE_INDEX] = + MESSAGE_LEN_JUDGE_RANGE; } static int is_str_msg_valid(char *msg, int str_len[], size_t str_num) @@ -308,7 +317,7 @@ static int verify_open_resp(size_t msg_len, void *msg) { struct open_response *resp = msg; - if (msg_len != sizeof(*resp)) + if (msg_len != sizeof(*resp) && msg_len != sizeof(*resp) - HMDFS_PAGE_SIZE - 1) return -EINVAL; return 0; @@ -856,6 +865,34 @@ static int hmdfs_drop_push_verify(int flag, size_t msg_len, void *msg) return 0; } +static int verify_drop_page_push_req(size_t msg_len, void *msg) +{ + struct drop_page_push_request *req = msg; + int str_len[] = {req->path_len}; + + if (req->path_len < 0 || req->path_len >= PATH_MAX) + return -EINVAL; + + if (msg_len != sizeof(*req) + req->path_len + 1) + return -EINVAL; + + if (is_str_msg_valid(req->buf, str_len, sizeof(str_len) / sizeof(int))) + return -EINVAL; + + return 0; +} + +static int hmdfs_drop_page_push_verify(int flag, size_t msg_len, void *msg) +{ + if (!msg || !msg_len) + return 0; + + if (flag == C_REQUEST) + return verify_drop_page_push_req(msg_len, msg); + + return 0; +} + typedef int (*hmdfs_message_verify_func)(int, size_t, void *); static const hmdfs_message_verify_func message_verify[F_SIZE] = { @@ -871,6 +908,7 @@ static const hmdfs_message_verify_func message_verify[F_SIZE] = { [F_SETATTR] = hmdfs_setattr_verify, [F_STATFS] = hmdfs_statfs_verify, [F_DROP_PUSH] = hmdfs_drop_push_verify, + [F_DROP_PAGE_PUSH] = hmdfs_drop_page_push_verify, [F_GETATTR] = hmdfs_getattr_verify, [F_GETXATTR] = hmdfs_getxattr_verify, [F_SETXATTR] = hmdfs_setxattr_verify, diff --git a/fs/hmdfs/comm/protocol.h b/fs/hmdfs/comm/protocol.h index beaa5adf4ba13782fc2c86afa4349d51c222f9a7..a8e795e04739d15730cf6a30ff9c50dc51f92fbb 100644 --- a/fs/hmdfs/comm/protocol.h +++ b/fs/hmdfs/comm/protocol.h @@ -13,6 +13,8 @@ #include #include +#define HMDFS_PREFETCH_FLAG 00000001 + struct hmdfs_cmd { __u8 reserved; __u8 cmd_flag; @@ -20,9 +22,21 @@ struct hmdfs_cmd { __u8 reserved2; } __packed; +static inline bool hm_isprefetch(__u8 flag) +{ + return (flag & HMDFS_PREFETCH_FLAG) == HMDFS_PREFETCH_FLAG; +} + +static inline void hm_setprefetch(__u8* flag) +{ + *flag |= HMDFS_PREFETCH_FLAG; +} + #define HMDFS_MSG_MAGIC 0xF7 #define HMDFS_MAX_MESSAGE_LEN (8 * 1024 * 1024) +#define HMDFS_PAGE_SIZE 4096 + struct hmdfs_head_cmd { __u8 magic; __u8 version; @@ -181,6 +195,7 @@ enum FILE_CMD { F_RESERVED_7 = 26, F_RESERVED_8 = 27, F_ATOMIC_OPEN = 28, + F_DROP_PAGE_PUSH = 29, F_SIZE, }; @@ -204,6 +219,8 @@ struct open_response { __le64 stable_ctime; __le32 stable_ctime_nsec; __le64 ichange_count; + __u8 read_success; + __u8 page[HMDFS_PAGE_SIZE]; } __packed; enum hmdfs_open_flags { @@ -332,6 +349,18 @@ struct drop_push_request { char path[0]; } __packed; +struct drop_page_push_request { + __le64 file_size; + __le64 ctime; + __le32 ctime_nsec; + __le64 mtime; + __le32 mtime_nsec; + __le64 stable_ctime; + __le32 stable_ctime_nsec; + __le32 path_len; + char buf[0]; +} __packed; + struct setattr_request { __le64 size; __le32 valid; diff --git a/fs/hmdfs/comm/socket_adapter.c b/fs/hmdfs/comm/socket_adapter.c index b9f35b9e1626b8bc9940d60c190daf3aaaebccfd..6b4bcde48d7f841c0d7002de40016b5f7caea9ba 100644 --- a/fs/hmdfs/comm/socket_adapter.c +++ b/fs/hmdfs/comm/socket_adapter.c @@ -43,6 +43,7 @@ static const request_callback s_recv_callbacks[F_SIZE] = { [F_SETATTR] = hmdfs_server_setattr, [F_STATFS] = hmdfs_server_statfs, [F_DROP_PUSH] = hmdfs_server_get_drop_push, + [F_DROP_PAGE_PUSH] = hmdfs_server_get_drop_page_push, [F_GETATTR] = hmdfs_server_getattr, [F_FSYNC] = hmdfs_server_fsync, [F_SYNCFS] = hmdfs_server_syncfs, @@ -835,6 +836,7 @@ static int hmdfs_request_recv(struct hmdfs_peer *con, case F_STATFS: case F_CONNECT_REKEY: case F_DROP_PUSH: + case F_DROP_PAGE_PUSH: case F_GETATTR: case F_FSYNC: case F_SYNCFS: @@ -1045,6 +1047,7 @@ static int hmdfs_response_recv(struct hmdfs_peer *con, case F_STATFS: case F_CONNECT_REKEY: case F_DROP_PUSH: + case F_DROP_PAGE_PUSH: case F_GETATTR: case F_FSYNC: case F_SYNCFS: diff --git a/fs/hmdfs/file_local.c b/fs/hmdfs/file_local.c index 41f65cfa4184023e0cfcba5d5f9ad4a85d18e4d3..6f12f2a867aa8a3108979eb267daec3dc0d869cc 100644 --- a/fs/hmdfs/file_local.c +++ b/fs/hmdfs/file_local.c @@ -64,6 +64,14 @@ int hmdfs_file_release_local(struct inode *inode, struct file *file) if (file->f_flags & (O_RDWR | O_WRONLY)) atomic_dec(&info->write_opened); + + spin_lock(&info->modify_lock); + if (info->modified){ + hmdfs_drop_remote_cache_pages(file_dentry(file)); + info->modified = false; + } + spin_unlock(&info->modify_lock); + file->private_data = NULL; fput(gfi->lower_file); kfree(gfi); @@ -112,6 +120,7 @@ static ssize_t hmdfs_local_read_iter(struct kiocb *iocb, struct iov_iter *iter) static void hmdfs_file_modified(struct file *file) { struct inode *inode = file_inode(file); + struct hmdfs_inode_info *info = hmdfs_i(inode); struct dentry *dentry = file_dentry(file); struct file *lower_file = hmdfs_f(file)->lower_file; struct inode *lower_inode = file_inode(lower_file); @@ -123,9 +132,13 @@ static void hmdfs_file_modified(struct file *file) if (!hmdfs_i_merge(hmdfs_i(inode))) update_inode_to_dentry(dentry, inode); + + spin_lock(&info->modify_lock); + info->modified = true; + spin_unlock(&info->modify_lock); } -ssize_t hmdfs_do_write_iter(struct file *file, struct iov_iter *iter, +ssize_t hmdfs_do_write_iter_local(struct file *file, struct iov_iter *iter, loff_t *ppos) { ssize_t ret; @@ -154,7 +167,7 @@ ssize_t hmdfs_do_write_iter(struct file *file, struct iov_iter *iter, ssize_t hmdfs_local_write_iter(struct kiocb *iocb, struct iov_iter *iter) { - return hmdfs_do_write_iter(iocb->ki_filp, iter, &iocb->ki_pos); + return hmdfs_do_write_iter_local(iocb->ki_filp, iter, &iocb->ki_pos); } int hmdfs_fsync_local(struct file *file, loff_t start, loff_t end, int datasync) diff --git a/fs/hmdfs/file_merge.c b/fs/hmdfs/file_merge.c index 8952674a23d4c4fc8e7729dc1290e88cb3766ace..3306e781b72c8706f30401e6a87832f9ebb1c125 100644 --- a/fs/hmdfs/file_merge.c +++ b/fs/hmdfs/file_merge.c @@ -532,9 +532,52 @@ static ssize_t hmdfs_merge_read_iter(struct kiocb *iocb, struct iov_iter *iter) return hmdfs_do_read_iter(iocb->ki_filp, iter, &iocb->ki_pos); } +static void hmdfs_file_modified(struct file *file) +{ + struct inode *inode = file_inode(file); + struct dentry *dentry = file_dentry(file); + struct file *lower_file = hmdfs_f(file)->lower_file; + struct inode *lower_inode = file_inode(lower_file); + + inode->i_atime = lower_inode->i_atime; + inode->i_ctime = lower_inode->i_ctime; + inode->i_mtime = lower_inode->i_mtime; + i_size_write(inode, i_size_read(lower_inode)); + + if (!hmdfs_i_merge(hmdfs_i(inode))) + update_inode_to_dentry(dentry, inode); +} + +ssize_t hmdfs_do_write_iter_merge(struct file *file, struct iov_iter *iter, + loff_t *ppos) +{ + ssize_t ret; + struct file *lower_file = hmdfs_f(file)->lower_file; + struct inode *inode = file_inode(file); + + if (!iov_iter_count(iter)) + return 0; + + inode_lock(inode); + + ret = file_remove_privs(file); + if (ret) + goto out_unlock; + + file_start_write(lower_file); + ret = vfs_iter_write(lower_file, iter, ppos, 0); + file_end_write(lower_file); + + hmdfs_file_modified(file); + +out_unlock: + inode_unlock(inode); + return ret; +} + ssize_t hmdfs_merge_write_iter(struct kiocb *iocb, struct iov_iter *iter) { - return hmdfs_do_write_iter(iocb->ki_filp, iter, &iocb->ki_pos); + return hmdfs_do_write_iter_merge(iocb->ki_filp, iter, &iocb->ki_pos); } int hmdfs_file_open_merge(struct inode *inode, struct file *file) @@ -575,6 +618,19 @@ int hmdfs_file_open_merge(struct inode *inode, struct file *file) return err; } +int hmdfs_file_release_merge(struct inode *inode, struct file *file) +{ + struct hmdfs_file_info *gfi = hmdfs_f(file); + struct hmdfs_inode_info *info = hmdfs_i(inode); + + if (file->f_flags & (O_RDWR | O_WRONLY)) + atomic_dec(&info->write_opened); + file->private_data = NULL; + fput(gfi->lower_file); + kfree(gfi); + return 0; +} + int hmdfs_file_flush_merge(struct file *file, fl_owner_t id) { struct hmdfs_file_info *gfi = hmdfs_f(file); @@ -827,9 +883,9 @@ const struct file_operations hmdfs_file_fops_merge = { .mmap = hmdfs_file_mmap_local, .open = hmdfs_file_open_merge, .flush = hmdfs_file_flush_merge, - .release = hmdfs_file_release_local, + .release = hmdfs_file_release_merge, .fsync = hmdfs_fsync_local, - .unlocked_ioctl = hmdfs_file_ioctl_merge, + .unlocked_ioctl = hmdfs_file_ioctl_merge, .compat_ioctl = hmdfs_file_ioctl_merge, .splice_read = generic_file_splice_read, .splice_write = iter_file_splice_write, diff --git a/fs/hmdfs/file_remote.c b/fs/hmdfs/file_remote.c index e3c012b73a835a59002dc773c3400262906793f4..1a840b8e41fdbbd6566262428effb7c42923122b 100644 --- a/fs/hmdfs/file_remote.c +++ b/fs/hmdfs/file_remote.c @@ -154,7 +154,16 @@ static int hmdfs_open_final_remote(struct hmdfs_inode_info *info, return 0; } -int hmdfs_do_open_remote(struct file *file, bool keep_cache) +static void hmdfs_set_page_content(struct page *page, const void *data) +{ + void *addr; + addr = kmap(page); + memcpy(addr, data, HMDFS_PAGE_SIZE); + SetPageUptodate(page); + kunmap(page); +} + +int hmdfs_do_open_remote(struct inode *inode, struct file *file, bool keep_cache) { struct hmdfs_inode_info *info = hmdfs_i(file_inode(file)); struct hmdfs_peer *conn = info->conn; @@ -175,6 +184,22 @@ int hmdfs_do_open_remote(struct file *file, bool keep_cache) } err = hmdfs_open_final_remote(info, &open_ret, file, keep_cache); + if (err) { + hmdfs_err("hmdfs_open_final_remote return failed with %d", err); + goto out_free; + } + + struct page *page = grab_cache_page(inode->i_mapping, 0); + if (!IS_ERR(page)) { + if (open_ret.read_success == 1) { + hmdfs_set_page_content(page, open_ret.page); + unlock_page(page); + } else { + unlock_page(page); + put_page(page); + err = open_ret.read_success; + } + } out_free: kfree(send_buf); @@ -247,7 +272,7 @@ static int hmdfs_remote_file_reopen(struct hmdfs_inode_info *info, */ if (fid.id != HMDFS_INODE_INVALID_FILE_ID) hmdfs_send_close(conn, &fid); - err = hmdfs_do_open_remote(filp, true); + err = hmdfs_do_open_remote(inode, filp, true); inode_unlock(inode); spin_lock(&info->fid_lock); @@ -337,10 +362,43 @@ int hmdfs_file_open_remote(struct inode *inode, struct file *file) int err = 0; inode_lock(inode); + + // NB: we only consider small file (size <= 1 KiB) here, otherwise we may need handle reading uncached pages when the file is not actually opened if (kref_read(ref) == 0) { - err = hmdfs_do_open_remote(file, false); - if (err == 0) - kref_init(ref); + // If the file is opened with intent to be modified, then we must communicate with the file holder + if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + if (info->need_reopen) { + err = hmdfs_do_open_remote(inode, file, false); + if (err >= 0) { + kref_init(ref); + info->need_reopen = err == EOPNOTSUPP? true : false; + err = 0; + } + } else { + if (info->writecache_expire && hmdfs_remote_write_cache_expired(info)) { + // different from above situation, here we set writecache_expire to 0, and truncate the inode page + // because we can omit the repeated judgement in hmdfs_open_final_remote + info->writecache_expire = 0; + truncate_inode_pages(inode->i_mapping, 0); + err = hmdfs_do_open_remote(inode, file, false); + if (err >= 0) { + kref_init(ref); + info->need_reopen = err == EOPNOTSUPP? true : false; + err = 0; + } + } else { + atomic64_set(&info->write_counter, 0); + info->getattr_isize = HMDFS_STALE_REMOTE_ISIZE; + } + } + } else { + err = hmdfs_do_open_remote(inode, file, false); + if (err >= 0) { + kref_init(ref); + info->need_reopen = err == EOPNOTSUPP? true : false; + err = 0; + } + } } else { kref_get(ref); } @@ -426,7 +484,9 @@ int hmdfs_file_release_remote(struct inode *inode, struct file *file) hmdfs_remote_del_wr_opened_inode(info->conn, info); inode_lock(inode); - kref_put(&info->ref, hmdfs_do_close_remote); + if (kref_read(&info->ref) > 0) + kref_put(&info->ref, hmdfs_do_close_remote); + hmdfs_remote_keep_writecache(inode, file); inode_unlock(inode); diff --git a/fs/hmdfs/hmdfs.h b/fs/hmdfs/hmdfs.h index c9940693f3e73e871443e27021bc101829e1dcfc..a7d80320f438126e9bbd59ddf4c2510aec253d12 100644 --- a/fs/hmdfs/hmdfs.h +++ b/fs/hmdfs/hmdfs.h @@ -32,8 +32,6 @@ #define HMDFS_IOC_GET_WRITEOPEN_CNT _IOR(HMDFS_IOC, 2, __u32) #define HMDFS_IOC_GET_DST_PATH _IOR(HMDFS_IOC, 3, __u32) - -#define HMDFS_PAGE_SIZE 4096 #define HMDFS_PAGE_OFFSET 12 /* max xattr value size, not include '\0' */ diff --git a/fs/hmdfs/hmdfs_client.c b/fs/hmdfs/hmdfs_client.c index 827d6b533f66bf74d8edc7f532ead4ed2ab85d1c..295c9297ca718e73304ee5bc8216e2bdc2ef9e09 100644 --- a/fs/hmdfs/hmdfs_client.c +++ b/fs/hmdfs/hmdfs_client.c @@ -29,6 +29,28 @@ static inline void free_sm_outbuf(struct hmdfs_send_command *sm) sm->out_buf = NULL; } +static struct hmdfs_time_t msec_to_timespec(unsigned int msec) +{ + struct hmdfs_time_t timespec = { + .tv_sec = msec / MSEC_PER_SEC, + .tv_nsec = (msec % MSEC_PER_SEC) * NSEC_PER_MSEC, + }; + + return timespec; +} + +static struct hmdfs_time_t hmdfs_current_kernel_time(void) +{ + struct hmdfs_time_t time; + +#if KERNEL_VERSION(4, 18, 0) < LINUX_VERSION_CODE + ktime_get_coarse_real_ts64(&time); +#else + time = current_kernel_time(); +#endif + return time; +} + int hmdfs_send_open(struct hmdfs_peer *con, const char *send_buf, __u8 file_type, struct hmdfs_open_ret *open_ret) { @@ -44,6 +66,7 @@ int hmdfs_send_open(struct hmdfs_peer *con, const char *send_buf, .local_filp = NULL, }; hmdfs_init_cmd(&sm.operations, F_OPEN); + hm_setprefetch(&sm.operations.reserved); if (!open_req) { ret = -ENOMEM; @@ -69,6 +92,13 @@ int hmdfs_send_open(struct hmdfs_peer *con, const char *send_buf, open_ret->remote_ctime.tv_nsec = le32_to_cpu(resp->ctime_nsec); open_ret->stable_ctime.tv_sec = le64_to_cpu(resp->stable_ctime); open_ret->stable_ctime.tv_nsec = le32_to_cpu(resp->stable_ctime_nsec); + if(sm.out_len == sizeof(struct open_response)) { + open_ret->read_success = resp->read_success; + if (open_ret->read_success) + memcpy(open_ret->page, resp->page, HMDFS_PAGE_SIZE); + } else { + open_ret->read_success = EOPNOTSUPP; + } out: free_sm_outbuf(&sm); @@ -1048,6 +1078,52 @@ void hmdfs_send_drop_push(struct hmdfs_peer *con, const char *path) kfree(dp_req); } +void hmdfs_send_drop_page_push(struct hmdfs_peer *con, const char *send_buf, struct inode *inode) +{ + int path_len = strlen(send_buf); + size_t send_len = sizeof(struct drop_page_push_request) + path_len + 1; + struct drop_page_push_request *dpp_req = kzalloc(send_len, GFP_KERNEL); + struct hmdfs_send_command sm = { + .data = dpp_req, + .len = send_len, + .out_buf = NULL, + .local_filp = NULL, + }; + + struct hmdfs_time_t current_time = hmdfs_current_kernel_time(); + struct hmdfs_time_t ctime = inode->i_ctime; + struct hmdfs_time_t precision = msec_to_timespec(con->sbi->dcache_precision); + + loff_t size = i_size_read(inode); + + hmdfs_init_cmd(&sm.operations, F_DROP_PAGE_PUSH); + if (!dpp_req) + return; + + dpp_req->file_size = cpu_to_le64(size); + dpp_req->ctime = cpu_to_le64(ctime.tv_sec); + dpp_req->ctime_nsec = cpu_to_le32(ctime.tv_nsec); + + precision = hmdfs_time_add(ctime, precision); + if (hmdfs_time_compare(¤t_time, &ctime) < 0) { + dpp_req->stable_ctime = cpu_to_le64(0); + dpp_req->stable_ctime_nsec = cpu_to_le32(0); + } else if (hmdfs_time_compare(¤t_time, &ctime) >= 0 && + hmdfs_time_compare(¤t_time, &precision) < 0) { + dpp_req->stable_ctime = dpp_req->ctime; + dpp_req->stable_ctime_nsec = dpp_req->ctime_nsec; + } else { + dpp_req->stable_ctime = cpu_to_le64(precision.tv_sec); + dpp_req->stable_ctime_nsec = cpu_to_le32(precision.tv_nsec); + } + + dpp_req->path_len = cpu_to_le32(path_len); + strcpy(dpp_req->buf, send_buf); + + hmdfs_sendmessage_request(con, &sm); + kfree(dpp_req); +} + static void *hmdfs_get_msg_next(struct hmdfs_peer *peer, int *id) { struct hmdfs_msg_idr_head *head = NULL; diff --git a/fs/hmdfs/hmdfs_client.h b/fs/hmdfs/hmdfs_client.h index ab2867dca4579fd15047c54f790c6ab61985fb90..25cda9b3ffba1f37b6ba244db6a065e91731b809 100644 --- a/fs/hmdfs/hmdfs_client.h +++ b/fs/hmdfs/hmdfs_client.h @@ -18,6 +18,8 @@ struct hmdfs_open_ret { __u64 ino; struct hmdfs_time_t remote_ctime; struct hmdfs_time_t stable_ctime; + __u8 read_success; + __u8 page[HMDFS_PAGE_SIZE]; }; struct hmdfs_writepage_context { diff --git a/fs/hmdfs/hmdfs_dentryfile.c b/fs/hmdfs/hmdfs_dentryfile.c index dc8b7a74f9a7eb78c42b0ebd648eae17633f5430..4c528ab20feb3feac4cd0ac5a7c3f03a6429271c 100644 --- a/fs/hmdfs/hmdfs_dentryfile.c +++ b/fs/hmdfs/hmdfs_dentryfile.c @@ -2326,6 +2326,8 @@ void hmdfs_add_remote_cache_list(struct hmdfs_peer *con, const char *dir_path) int err = 0; struct remotecache_item *item = NULL; struct remotecache_item *item_temp = NULL; + // This path is local view + // i.e. /mnt/hmdfs//account/device_view/local/data// struct path path, root_path; struct hmdfs_dentry_info *d_info = NULL; @@ -2374,6 +2376,38 @@ void hmdfs_add_remote_cache_list(struct hmdfs_peer *con, const char *dir_path) path_put(&root_path); } +void hmdfs_add_remote_page_cache_list(struct hmdfs_peer *con, struct file *file) +{ + struct remotecache_item *item = NULL; + struct remotecache_item *item_temp = NULL; + struct hmdfs_dentry_info *d_info = NULL; + + d_info = hmdfs_d(file->f_path.dentry); + if (!d_info) + return; + + /* find duplicate con */ + mutex_lock(&d_info->remote_cache_list_lock); + list_for_each_entry_safe(item, item_temp, + &(d_info->remote_cache_list_head), list) { + if (item->con->device_id == con->device_id) { + mutex_unlock(&d_info->remote_cache_list_lock); + return; + } + } + + item = kzalloc(sizeof(*item), GFP_KERNEL); + if (!item) { + mutex_unlock(&d_info->remote_cache_list_lock); + return; + } + + item->con = con; + item->drop_flag = 0; + list_add(&(item->list), &(d_info->remote_cache_list_head)); + mutex_unlock(&d_info->remote_cache_list_lock); +} + int hmdfs_drop_remote_cache_dents(struct dentry *dentry) { struct path lower_path; @@ -2430,6 +2464,45 @@ int hmdfs_drop_remote_cache_dents(struct dentry *dentry) return 0; } +int hmdfs_drop_remote_cache_pages(struct dentry *dentry) +{ + struct remotecache_item *item = NULL; + struct remotecache_item *item_temp = NULL; + struct hmdfs_dentry_info *d_info = NULL; + char *relative_path = NULL; + + if (!dentry) { + hmdfs_err("dentry null and return"); + return 0; + } + + d_info = hmdfs_d(dentry); + if (!d_info) { + hmdfs_err("d_info null and return"); + return 0; + } + relative_path = hmdfs_get_dentry_relative_path(dentry); + if (!relative_path) { + hmdfs_err("get dentry relative path failed"); + return 0; + } + mutex_lock(&d_info->remote_cache_list_lock); + list_for_each_entry_safe(item, item_temp, + &(d_info->remote_cache_list_head), list) { + if (item->drop_flag == 1) { + item->drop_flag = 0; + continue; + } + hmdfs_send_drop_page_push(item->con, relative_path, dentry->d_inode); + list_del(&item->list); + kfree(item); + } + mutex_unlock(&d_info->remote_cache_list_lock); + + kfree(relative_path); + return 0; +} + /* Clear the dentry cache files of target directory */ int hmdfs_clear_cache_dents(struct dentry *dentry, bool remove_cache) { diff --git a/fs/hmdfs/hmdfs_dentryfile.h b/fs/hmdfs/hmdfs_dentryfile.h index b3907ce1b86e1179ad333080be175980b2af74e1..c696ff6cd653d641889619040d49ec5a42f26714 100644 --- a/fs/hmdfs/hmdfs_dentryfile.h +++ b/fs/hmdfs/hmdfs_dentryfile.h @@ -211,6 +211,7 @@ struct clearcache_item { }; void hmdfs_add_remote_cache_list(struct hmdfs_peer *con, const char *dir_path); +void hmdfs_add_remote_page_cache_list(struct hmdfs_peer *con, struct file *file); struct remotecache_item { struct hmdfs_peer *con; @@ -245,7 +246,9 @@ struct cache_file_callback { }; int hmdfs_drop_remote_cache_dents(struct dentry *dentry); +int hmdfs_drop_remote_cache_pages(struct dentry *dentry); void hmdfs_send_drop_push(struct hmdfs_peer *con, const char *path); +void hmdfs_send_drop_page_push(struct hmdfs_peer *con, const char *send_buf, struct inode *inode); void hmdfs_mark_drop_flag(uint64_t device_id, struct dentry *dentry); void hmdfs_clear_drop_flag(struct dentry *dentry); void delete_in_cache_file(uint64_t dev_id, struct dentry *dentry); diff --git a/fs/hmdfs/hmdfs_device_view.h b/fs/hmdfs/hmdfs_device_view.h index a1f792d9eb0f68ad1ea5eaabf75a6b09f2f5178f..d745c321d8316858cbce2a579e3783040d7436e9 100644 --- a/fs/hmdfs/hmdfs_device_view.h +++ b/fs/hmdfs/hmdfs_device_view.h @@ -128,8 +128,11 @@ loff_t hmdfs_file_llseek_local(struct file *file, loff_t offset, int whence); ssize_t hmdfs_do_read_iter(struct file *file, struct iov_iter *iter, loff_t *ppos); -ssize_t hmdfs_do_write_iter(struct file *file, struct iov_iter *iter, - loff_t *ppos); +ssize_t hmdfs_do_write_iter_merge(struct file *file, struct iov_iter *iter, + loff_t *ppos); + +ssize_t hmdfs_do_write_iter_local(struct file *file, struct iov_iter *iter, + loff_t *ppos); int hmdfs_file_release_local(struct inode *inode, struct file *file); int hmdfs_file_mmap_local(struct file *file, struct vm_area_struct *vma); diff --git a/fs/hmdfs/hmdfs_server.c b/fs/hmdfs/hmdfs_server.c index 34b4d579f9d2ce8d3a7b96083d67f93973b0d16f..b50238d47e05a9877fceaf67a75798f4e6643d49 100644 --- a/fs/hmdfs/hmdfs_server.c +++ b/fs/hmdfs/hmdfs_server.c @@ -460,7 +460,10 @@ static void hmdfs_update_open_response(struct hmdfs_peer *con, msec_to_timespec(con->sbi->dcache_precision); loff_t size = info->stat_valid ? info->stat.size : i_size_read(info->inode); + loff_t pos = 0; + ssize_t readsize = 0; + // NB: info->real_ino is the lower_file's i_ino and i_igeneration, not the info->file's resp->ino = cpu_to_le64(info->real_ino); resp->file_ver = cpu_to_le64(hmdfs_server_pack_fid_ver(con, cmd)); resp->file_id = cpu_to_le32(info->file_id); @@ -488,6 +491,17 @@ static void hmdfs_update_open_response(struct hmdfs_peer *con, resp->stable_ctime = cpu_to_le64(precision.tv_sec); resp->stable_ctime_nsec = cpu_to_le32(precision.tv_nsec); } + + if(hm_isprefetch(cmd->operations.reserved)) { + readsize = kernel_read(info->file, resp->page, HMDFS_PAGE_SIZE, &pos); + if (readsize < 0) { + resp->read_success = 0; + } else { + resp->read_success = 1; + if (readsize != HMDFS_PAGE_SIZE) + memset(resp->page + readsize, 0, HMDFS_PAGE_SIZE - readsize); + } + } } static int hmdfs_get_open_info(struct hmdfs_peer *con, uint8_t file_type, @@ -534,66 +548,6 @@ static int hmdfs_get_open_info(struct hmdfs_peer *con, uint8_t file_type, return 0; } -void hmdfs_server_open(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, - void *data) -{ - struct open_request *recv = data; - int sizeread = sizeof(struct open_response); - struct open_response *resp = NULL; - struct hmdfs_open_info *info = NULL; - int ret = 0; - - trace_hmdfs_server_open_enter(con, recv); - - resp = kzalloc(sizeread, GFP_KERNEL); - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!resp || !info) { - ret = -ENOMEM; - goto err_free; - } - - if (path_contain_dotdot(recv->buf, recv->path_len)) { - ret = -EINVAL; - goto err_free; - } - - info->file = hmdfs_open_file(con, recv->buf, recv->file_type, - &info->file_id); - if (IS_ERR(info->file)) { - ret = PTR_ERR(info->file); - goto err_free; - } - - ret = hmdfs_get_open_info(con, recv->file_type, recv->buf, info); - if (ret) - goto err_close; - - hmdfs_update_open_response(con, cmd, info, resp); - - trace_hmdfs_server_open_exit(con, resp, info->file, 0); - ret = hmdfs_sendmessage_response(con, cmd, sizeread, resp, 0); - if (ret) { - hmdfs_err("sending msg response failed, file_id %d, err %d", - info->file_id, ret); - remove_file_from_conn(con, info->file_id); - hmdfs_close_path(info->file); - } - hmdfs_close_path(info->file); - kfree(resp); - kfree(info); - return; - -err_close: - hmdfs_close_path(info->file); - remove_file_from_conn(con, info->file_id); - hmdfs_close_path(info->file); -err_free: - kfree(resp); - kfree(info); - trace_hmdfs_server_open_exit(con, NULL, NULL, ret); - hmdfs_send_err_response(con, cmd, ret); -} - static int hmdfs_check_and_create(struct path *path_parent, struct dentry *dentry, uint64_t device_id, umode_t mode, bool is_excl) @@ -1050,7 +1004,7 @@ static int server_lookup(struct hmdfs_peer *peer, const char *req_path, goto out_noroot; err = vfs_path_lookup(root_path.dentry, root_path.mnt, req_path, - LOOKUP_DIRECTORY, path); + 0, path); path_put(&root_path); out_noroot: return err; @@ -1087,6 +1041,74 @@ static char *server_lookup_lower(struct hmdfs_peer *peer, const char *req_path, return err ? ERR_PTR(err) : lo_p_name; } +void hmdfs_server_open(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, + void *data) +{ + struct open_request *recv = data; + bool is_prefetch = hm_isprefetch(cmd->operations.reserved); + int sizeread = sizeof(struct open_response) - (is_prefetch ? + 0 : HMDFS_PAGE_SIZE + 1); + struct open_response *resp = NULL; + struct hmdfs_open_info *info = NULL; + int ret = 0; + + trace_hmdfs_server_open_enter(con, recv); + + resp = kzalloc(sizeread, GFP_KERNEL); + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!resp || !info) { + ret = -ENOMEM; + goto err_free; + } + + if (path_contain_dotdot(recv->buf, recv->path_len)) { + ret = -EINVAL; + goto err_free; + } + + info->file = hmdfs_open_file(con, recv->buf, recv->file_type, + &info->file_id); + + if (IS_ERR(info->file)) { + ret = PTR_ERR(info->file); + goto err_free; + } + + ret = hmdfs_get_open_info(con, recv->file_type, recv->buf, info); + if (ret) + goto err_close; + + hmdfs_update_open_response(con, cmd, info, resp); + + trace_hmdfs_server_open_exit(con, resp, info->file, 0); + ret = hmdfs_sendmessage_response(con, cmd, sizeread, resp, 0); + if (ret) { + hmdfs_err("sending msg response failed, file_id %d, err %d", + info->file_id, ret); + remove_file_from_conn(con, info->file_id); + goto out; + } + + if(is_prefetch) + hmdfs_add_remote_page_cache_list(con, info->file); + +out: + hmdfs_close_path(info->file); + kfree(resp); + kfree(info); + return; + +err_close: + hmdfs_close_path(info->file); + remove_file_from_conn(con, info->file_id); + hmdfs_close_path(info->file); +err_free: + kfree(resp); + kfree(info); + trace_hmdfs_server_open_exit(con, NULL, NULL, ret); + hmdfs_send_err_response(con, cmd, ret); +} + void hmdfs_server_readdir(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, void *data) { @@ -1441,6 +1463,7 @@ static int hmdfs_filldir_real(struct dir_context *ctx, const char *name, } if (d_type == DT_REG || d_type == DT_DIR) { + // gc->file is dentry_file, the anonymous tmp_file create_dentry(child, d_inode(child), gc->file, gc->sbi); gc->num++; } else if (d_type == DT_LNK) { @@ -1500,12 +1523,14 @@ struct file *hmdfs_server_rebuild_dents(struct hmdfs_sb_info *sbi, struct file *dentry_file = NULL; struct hmdfs_dcache_header header; + // create a anonymous tmp_file in sbi->cache_dir dentry_file = create_local_dentry_file_cache(sbi); if (IS_ERR(dentry_file)) { hmdfs_err("file create failed err=%ld", PTR_ERR(dentry_file)); return dentry_file; } + // path is the lower path of the target dir file = dentry_open(path, O_RDONLY | O_DIRECTORY, current_cred()); if (IS_ERR(file)) { err = PTR_ERR(file); @@ -1556,6 +1581,10 @@ void hmdfs_server_writepage(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, ssize_t ret; int err = 0; + struct remotecache_item *item = NULL; + struct remotecache_item *item_temp = NULL; + struct hmdfs_dentry_info *d_info = NULL; + file_id = le32_to_cpu(writepage_recv->file_id); file_ver = le64_to_cpu(writepage_recv->file_ver); file = get_file_by_fid_and_ver(con, cmd, file_id, file_ver); @@ -1567,12 +1596,24 @@ void hmdfs_server_writepage(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, err = PTR_ERR(file); goto out; } + d_info = hmdfs_d(file->f_path.dentry); pos = (loff_t)le64_to_cpu(writepage_recv->index) << HMDFS_PAGE_OFFSET; count = le32_to_cpu(writepage_recv->count); ret = kernel_write(file, writepage_recv->buf, count, &pos); if (ret != count) err = -EIO; + else if (d_info) { + mutex_lock(&d_info->remote_cache_list_lock); + list_for_each_entry_safe(item, item_temp, + &(d_info->remote_cache_list_head), list) { + if (item->con->device_id == con->device_id) { + item->drop_flag = 1; + break; + } + } + mutex_unlock(&d_info->remote_cache_list_lock); + } hmdfs_close_path(file); out: @@ -2123,3 +2164,88 @@ void hmdfs_server_get_drop_push(struct hmdfs_peer *con, quickack: set_conn_sock_quickack(con); } + +static struct drop_page_push_recv init_drop_page_push_recv(void *data) +{ + struct drop_page_push_request *dpp_recv = data; + struct drop_page_push_recv dppr = { + .file_size = le64_to_cpu(dpp_recv->file_size), + .path_len = le32_to_cpu(dpp_recv->path_len), + .buf = dpp_recv->buf, + }; + dppr.remote_ctime.tv_sec = le64_to_cpu(dpp_recv->ctime); + dppr.remote_ctime.tv_nsec = le64_to_cpu(dpp_recv->ctime_nsec); + dppr.stable_ctime.tv_sec = le64_to_cpu(dpp_recv->stable_ctime); + dppr.stable_ctime.tv_nsec = le64_to_cpu(dpp_recv->stable_ctime_nsec); + + return dppr; +} + +void hmdfs_server_get_drop_page_push(struct hmdfs_peer *con, + struct hmdfs_head_cmd *cmd, void *data) +{ + struct drop_page_push_recv dpp_recv = init_drop_page_push_recv(data); + struct path root_path, path; + struct inode *inode; + struct hmdfs_inode_info *info; + char *tmp_path = NULL; + int err; + + // Learn from hmdfs_server_get_drop_push + const char *root_name = con->sbi->real_dst; + if (path_contain_dotdot(dpp_recv.buf, dpp_recv.path_len)) { + err = -EINVAL; + goto quickack; + } + + err = kern_path(root_name, 0, &root_path); + if (err) { + hmdfs_err("kern_path failed at %s, err = %d", root_name, err); + goto quickack; + } + + tmp_path = kzalloc(PATH_MAX, GFP_KERNEL); + if (!tmp_path) + goto out_kfree; + snprintf(tmp_path, PATH_MAX, "/" DEVICE_VIEW_ROOT "/%s%s", + con->cid, dpp_recv.buf); + + err = vfs_path_lookup(root_path.dentry, root_path.mnt, tmp_path, 0, + &path); + if (err) { + hmdfs_info("path found failed at %s, err = %d", dpp_recv.buf, err); + goto out_tfree; + } + + inode = d_inode(path.dentry); + info = hmdfs_i(inode); + + inode_lock(inode); + + /* + * It doesn't make sense to update metadata here but leaving the data obsolete. + * But how to design here? Should we also transport the data here? + * Transporting data means we may never open the file twice, + * which may corrupt file reference counter in server when the file is not opened but the page cache is missing. + */ + // inode->i_ctime = dpp_recv.remote_ctime; + // info->remote_ctime = dpp_recv.remote_ctime; + // info->stable_ctime = dpp_recv.stable_ctime; + + // i_size_write(inode, dpp_recv.file_size); + + info->need_reopen = true; + + inode_unlock(inode); + + path_put(&path); + +out_tfree: + kfree(tmp_path); + +out_kfree: + path_put(&root_path); + +quickack: + set_conn_sock_quickack(con); +} \ No newline at end of file diff --git a/fs/hmdfs/hmdfs_server.h b/fs/hmdfs/hmdfs_server.h index e832c7ff85be06486202f362ee2d6187fb4a002d..0ca5f883abb589702d94d6d1ff4bafa31d1ac802 100644 --- a/fs/hmdfs/hmdfs_server.h +++ b/fs/hmdfs/hmdfs_server.h @@ -20,6 +20,14 @@ #define DATA_SEC_LEVEL_LABEL "user.security" #define DATA_SEC_LEVEL_LENGTH 10 +struct drop_page_push_recv { + __u64 file_size; + struct hmdfs_time_t remote_ctime; + struct hmdfs_time_t stable_ctime; + __u32 path_len; + char *buf; +}; + static inline void hmdfs_send_err_response(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, int err) { @@ -74,6 +82,8 @@ void hmdfs_server_listxattr(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, void *data); void hmdfs_server_get_drop_push(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, void *data); +void hmdfs_server_get_drop_page_push(struct hmdfs_peer *con, + struct hmdfs_head_cmd *cmd, void *data); void __init hmdfs_server_add_node_evt_cb(void); #endif diff --git a/fs/hmdfs/inode.h b/fs/hmdfs/inode.h index fb9bd2929d581e6e48dee17bd369962869440e02..ddb14f127851a3677692f4bfd0777522f0773924 100644 --- a/fs/hmdfs/inode.h +++ b/fs/hmdfs/inode.h @@ -69,6 +69,9 @@ struct hmdfs_inode_info { struct inode *lower_inode; // for local/merge inode struct hmdfs_peer *conn; // for remote inode struct kref ref; + bool need_reopen; + spinlock_t modify_lock; + bool modified; spinlock_t fid_lock; struct hmdfs_fid fid; unsigned long fid_flags; diff --git a/fs/hmdfs/inode_local.c b/fs/hmdfs/inode_local.c index da1db4cbc7c58a6e5cc7e01429c943cb802f553a..087d179bec2e3fc4eb7f0299da066b6a1e517f4d 100644 --- a/fs/hmdfs/inode_local.c +++ b/fs/hmdfs/inode_local.c @@ -455,6 +455,8 @@ int hmdfs_create_local_dentry(struct inode *dir, struct dentry *dentry, d_add(dentry, child_inode); out_created: + // It seems that we should use local_view here + // i.e. /mnt/hmdfs//account/device_view/local/data// hmdfs_drop_remote_cache_dents(dentry->d_parent); out: if (error) { diff --git a/fs/hmdfs/main.c b/fs/hmdfs/main.c index 10d37cbac2efaae86291fc00a8021ac61e876afd..5e3f7bacda4850229d5ca15ebb4721a52813d5c9 100644 --- a/fs/hmdfs/main.c +++ b/fs/hmdfs/main.c @@ -314,6 +314,9 @@ static struct inode *hmdfs_alloc_inode(struct super_block *sb) if (!gi) return NULL; memset(gi, 0, offsetof(struct hmdfs_inode_info, vfs_inode)); + gi->need_reopen = true; + gi->modified = false; + spin_lock_init(&gi->modify_lock); INIT_LIST_HEAD(&gi->wb_list); init_rwsem(&gi->wpage_sem); gi->getattr_isize = HMDFS_STALE_REMOTE_ISIZE; @@ -697,6 +700,7 @@ static void hmdfs_init_cmd_timeout(struct hmdfs_sb_info *sbi) set_cmd_timeout(sbi, F_STATFS, TIMEOUT_COMMON); set_cmd_timeout(sbi, F_CONNECT_REKEY, TIMEOUT_NONE); set_cmd_timeout(sbi, F_DROP_PUSH, TIMEOUT_NONE); + set_cmd_timeout(sbi, F_DROP_PAGE_PUSH, TIMEOUT_NONE); set_cmd_timeout(sbi, F_GETATTR, TIMEOUT_COMMON); set_cmd_timeout(sbi, F_FSYNC, TIMEOUT_90S); set_cmd_timeout(sbi, F_SYNCFS, TIMEOUT_30S);