+static inline int ll_dom_readpage(void *data, struct page *page)
+{
+ struct niobuf_local *lnb = data;
+ void *kaddr;
+
+ kaddr = ll_kmap_atomic(page, KM_USER0);
+ 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);
+ ll_kunmap_atomic(kaddr, KM_USER0);
+ unlock_page(page);
+
+ return 0;
+}
+
+void ll_dom_finish_open(struct inode *inode, struct ptlrpc_request *req,
+ struct lookup_intent *it)
+{
+ 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;
+
+ 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) {
+ 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;
+ }
+
+ 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 {
+ 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;
+ }
+ put_page(vmpage);
+ index++;
+ } while (rnb->rnb_len > (index << PAGE_SHIFT));
+ EXIT;
+}
+