+ if (unlikely(atomic_dec_and_test(&dreq->complete))) {
+ nfs_free_user_pages(dreq->pages, dreq->npages, 1);
+ wake_up(&dreq->wait);
+ kref_put(&dreq->kref, nfs_direct_req_release);
+ }
+}
+
+/**
+ * nfs_direct_read_schedule - dispatch NFS READ operations for a direct read
+ * @dreq: address of nfs_direct_req struct for this request
+ * @inode: target inode
+ * @ctx: target file open context
+ * @user_addr: starting address of this segment of user's buffer
+ * @count: size of this segment
+ * @file_offset: offset in file to begin the operation
+ *
+ * For each nfs_read_data struct that was allocated on the list, dispatch
+ * an NFS READ operation
+ */
+static void nfs_direct_read_schedule(struct nfs_direct_req *dreq,
+ struct inode *inode, struct nfs_open_context *ctx,
+ unsigned long user_addr, size_t count, loff_t file_offset)
+{
+ struct list_head *list = &dreq->list;
+ struct page **pages = dreq->pages;
+ unsigned int curpage, pgbase;
+ unsigned int rsize = NFS_SERVER(inode)->rsize;
+
+ curpage = 0;
+ pgbase = user_addr & ~PAGE_MASK;
+ do {
+ struct nfs_read_data *data;
+ unsigned int bytes;
+
+ bytes = rsize;
+ if (count < rsize)
+ bytes = count;
+
+ data = list_entry(list->next, struct nfs_read_data, pages);
+ list_del_init(&data->pages);
+
+ data->inode = inode;
+ data->cred = ctx->cred;
+ data->args.fh = NFS_FH(inode);
+ data->args.context = ctx;
+ data->args.offset = file_offset;
+ data->args.pgbase = pgbase;
+ data->args.pages = &pages[curpage];
+ data->args.count = bytes;
+ data->res.fattr = &data->fattr;
+ data->res.eof = 0;
+ data->res.count = bytes;
+
+ NFS_PROTO(inode)->read_setup(data);
+
+ data->task.tk_cookie = (unsigned long) inode;
+ data->task.tk_calldata = data;
+ data->task.tk_release = nfs_readdata_release;
+ data->complete = nfs_direct_read_result;