+static inline int ll_dom_readpage(void *data, struct page *page)
+{
+ struct niobuf_local *lnb = data;
+ void *kaddr;
+ int rc = 0;
+
+ struct inode *inode = page2inode(page);
+
+ kaddr = kmap_atomic(page);
+ memcpy(kaddr, lnb->lnb_data, lnb->lnb_len);
+ if (lnb->lnb_len < PAGE_SIZE)
+ memset(kaddr + lnb->lnb_len, 0,
+ PAGE_SIZE - lnb->lnb_len);
+ flush_dcache_page(page);
+ SetPageUptodate(page);
+ kunmap_atomic(kaddr);
+
+ if (inode && IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode)) {
+ if (!llcrypt_has_encryption_key(inode))
+ CDEBUG(D_SEC, "no enc key for "DFID"\n",
+ PFID(ll_inode2fid(inode)));
+ else {
+ unsigned int offs = 0;
+
+ while (offs < PAGE_SIZE) {
+ /* decrypt only if page is not empty */
+ if (memcmp(page_address(page) + offs,
+ page_address(ZERO_PAGE(0)),
+ LUSTRE_ENCRYPTION_UNIT_SIZE) == 0)
+ break;
+
+ rc = llcrypt_decrypt_pagecache_blocks(page,
+ LUSTRE_ENCRYPTION_UNIT_SIZE,
+ offs);
+ if (rc)
+ break;
+
+ offs += LUSTRE_ENCRYPTION_UNIT_SIZE;
+ }
+ }
+ }
+ unlock_page(page);
+
+ return rc;
+}
+
+void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req)
+{
+ struct lu_env *env;
+ struct cl_io *io;
+ struct ll_inode_info *lli = ll_i2info(inode);
+ struct cl_object *obj = lli->lli_clob;
+ struct address_space *mapping = inode->i_mapping;
+ struct page *vmpage;
+ struct niobuf_remote *rnb;
+ struct mdt_body *body;
+ char *data;
+ unsigned long index, start;
+ struct niobuf_local lnb;
+ __u16 refcheck;
+ int rc;
+
+ ENTRY;
+
+ if (obj == NULL)
+ RETURN_EXIT;
+
+ if (!req_capsule_field_present(&req->rq_pill, &RMF_NIOBUF_INLINE,
+ RCL_SERVER))
+ RETURN_EXIT;
+
+ rnb = req_capsule_server_get(&req->rq_pill, &RMF_NIOBUF_INLINE);
+ if (rnb == NULL || rnb->rnb_len == 0)
+ RETURN_EXIT;
+
+ /* LU-11595: Server may return whole file and that is OK always or
+ * it may return just file tail and its offset must be aligned with
+ * client PAGE_SIZE to be used on that client, if server's PAGE_SIZE is
+ * smaller then offset may be not aligned and that data is just ignored.
+ */
+ if (rnb->rnb_offset & ~PAGE_MASK)
+ RETURN_EXIT;
+
+ /* Server returns whole file or just file tail if it fills in reply
+ * buffer, in both cases total size should be equal to the file size.
+ */
+ body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY);
+ if (rnb->rnb_offset + rnb->rnb_len != body->mbo_dom_size &&
+ !(inode && IS_ENCRYPTED(inode))) {
+ CERROR("%s: server returns off/len %llu/%u but size %llu\n",
+ ll_i2sbi(inode)->ll_fsname, rnb->rnb_offset,
+ rnb->rnb_len, body->mbo_dom_size);
+ RETURN_EXIT;
+ }
+
+ env = cl_env_get(&refcheck);
+ if (IS_ERR(env))
+ RETURN_EXIT;
+ io = vvp_env_thread_io(env);
+ io->ci_obj = obj;
+ io->ci_ignore_layout = 1;
+ rc = cl_io_init(env, io, CIT_MISC, obj);
+ if (rc)
+ GOTO(out_io, rc);
+
+ CDEBUG(D_INFO, "Get data along with open at %llu len %i, size %llu\n",
+ rnb->rnb_offset, rnb->rnb_len, body->mbo_dom_size);
+
+ data = (char *)rnb + sizeof(*rnb);
+
+ lnb.lnb_file_offset = rnb->rnb_offset;
+ start = lnb.lnb_file_offset >> PAGE_SHIFT;
+ index = 0;
+ LASSERT((lnb.lnb_file_offset & ~PAGE_MASK) == 0);
+ lnb.lnb_page_offset = 0;
+ do {
+ struct cl_page *page;
+
+ lnb.lnb_data = data + (index << PAGE_SHIFT);
+ lnb.lnb_len = rnb->rnb_len - (index << PAGE_SHIFT);
+ if (lnb.lnb_len > PAGE_SIZE)
+ lnb.lnb_len = PAGE_SIZE;
+
+ vmpage = read_cache_page(mapping, index + start,
+ ll_dom_readpage, &lnb);
+ if (IS_ERR(vmpage)) {
+ CWARN("%s: cannot fill page %lu for "DFID
+ " with data: rc = %li\n",
+ ll_i2sbi(inode)->ll_fsname, index + start,
+ PFID(lu_object_fid(&obj->co_lu)),
+ PTR_ERR(vmpage));
+ break;
+ }
+ lock_page(vmpage);
+ if (vmpage->mapping == NULL) {
+ unlock_page(vmpage);
+ put_page(vmpage);
+ /* page was truncated */
+ break;
+ }
+ /* attach VM page to CL page cache */
+ page = cl_page_find(env, obj, vmpage->index, vmpage,
+ CPT_CACHEABLE);
+ if (IS_ERR(page)) {
+ ClearPageUptodate(vmpage);
+ unlock_page(vmpage);
+ put_page(vmpage);
+ break;
+ }
+ cl_page_export(env, page, 1);
+ cl_page_put(env, page);
+ unlock_page(vmpage);
+ put_page(vmpage);
+ index++;
+ } while (rnb->rnb_len > (index << PAGE_SHIFT));
+
+out_io:
+ cl_io_fini(env, io);
+ cl_env_put(env, &refcheck);
+
+ EXIT;
+}
+