/* * New rpc_call implementation */ int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags) { struct rpc_task my_task, *task = &my_task; sigset_t oldset; int status; /* If this client is slain all further I/O fails */ if (clnt->cl_dead) return -EIO; if (flags & RPC_TASK_ASYNC) { printk("rpc_call_sync: Illegal flag combination for synchronous task\n"); flags &= ~RPC_TASK_ASYNC; } rpc_clnt_sigmask(clnt, &oldset); /* Create/initialize a new RPC task */ rpc_init_task(task, clnt, NULL, flags); rpc_call_setup(task, msg, 0); /* Set up the call info struct and execute the task */ if (task->tk_status == 0) status = rpc_execute(task); else { status = task->tk_status; rpc_release_task(task); } rpc_clnt_sigunmask(clnt, &oldset); return status; }
/* * New rpc_call implementation */ int rpc_do_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags, rpc_action func, void *data) { struct rpc_task my_task, *task = &my_task; sigset_t oldset; int async, status; /* If this client is slain all further I/O fails */ if (clnt->cl_dead) return -EIO; rpc_clnt_sigmask(clnt, &oldset); /* Create/initialize a new RPC task */ if ((async = (flags & RPC_TASK_ASYNC)) != 0) { if (!func) func = rpc_default_callback; status = -ENOMEM; if (!(task = rpc_new_task(clnt, func, flags))) goto out; task->tk_calldata = data; } else { rpc_init_task(task, clnt, NULL, flags); } /* Bind the user cred, set up the call info struct and * execute the task */ if (rpcauth_lookupcred(task) != NULL) { rpc_call_setup(task, proc, argp, resp, 0); rpc_execute(task); } else async = 0; status = 0; if (!async) { status = task->tk_status; rpc_release_task(task); } out: rpc_clnt_sigunmask(clnt, &oldset); return status; }
int nfs_reqlist_init(struct nfs_server *server) { struct nfs_reqlist *cache; struct rpc_task *task; int status; dprintk("NFS: writecache_init\n"); lock_kernel(); status = -ENOMEM; /* Create the RPC task */ if (!(task = rpc_new_task(server->client, NULL, RPC_TASK_ASYNC))) goto out_unlock; cache = server->rw_requests; status = 0; if (cache->task) goto out_unlock; task->tk_calldata = server; cache->task = task; /* Run the task */ cache->runat = jiffies; cache->auth = server->client->cl_auth; task->tk_action = nfs_flushd; task->tk_exit = nfs_flushd_exit; rpc_execute(task); unlock_kernel(); return 0; out_unlock: if (task) rpc_release_task(task); unlock_kernel(); return status; }
/* * New rpc_call implementation */ int rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags, rpc_action callback, void *data) { struct rpc_task *task; sigset_t oldset; int status; /* If this client is slain all further I/O fails */ if (clnt->cl_dead) return -EIO; flags |= RPC_TASK_ASYNC; rpc_clnt_sigmask(clnt, &oldset); /* Create/initialize a new RPC task */ if (!callback) callback = rpc_default_callback; status = -ENOMEM; if (!(task = rpc_new_task(clnt, callback, flags))) goto out; task->tk_calldata = data; rpc_call_setup(task, msg, 0); /* Set up the call info struct and execute the task */ if (task->tk_status == 0) status = rpc_execute(task); else { status = task->tk_status; rpc_release_task(task); } out: rpc_clnt_sigunmask(clnt, &oldset); return status; }
VCOS_STATUS_T vcos_llthread_create(VCOS_LLTHREAD_T *thread, const char *name, VCOS_LLTHREAD_ENTRY_FN_T entry, void *arg, void *stack, VCOS_UNSIGNED stacksz, VCOS_UNSIGNED priority, VCOS_UNSIGNED affinity, VCOS_UNSIGNED timeslice, VCOS_UNSIGNED autostart) { vcos_assert(priority >= VCOS_THREAD_PRI_MIN); vcos_assert(priority <= VCOS_THREAD_PRI_MAX); vcos_assert((affinity & ~VCOS_AFFINITY_MASK) == 0); vcos_assert((stacksz & 3) == 0); vcos_assert(timeslice < 1024); vcos_assert((autostart == VCOS_START) || (autostart == VCOS_NO_START)); /* Extra restrictions for the RPC-based implementation */ vcos_assert(stack == NULL); if ( rtos_get_cpu_number() == 0 && affinity == VCOS_AFFINITY_CPU1 && vcos_none_vpu1_thread == NULL ) { need_rpc(); vcos_none_vpu1_thread = thread; thread->suspended = !autostart; rpc_function = (int(*)())launcher; rpc_execute( entry, arg ); return VCOS_SUCCESS; } else { vcos_assert(0); return VCOS_EINVAL; } }
static int rbio_submit(struct ploop_io * io, struct nfs_read_data * nreq, const struct rpc_call_ops * cb) { struct nfs_open_context *ctx = nfs_file_open_context(io->files.file); struct inode *inode = io->files.inode; struct rpc_task *task; struct rpc_message msg = { .rpc_cred = ctx->cred, }; struct rpc_task_setup task_setup_data = { .rpc_client = NFS_CLIENT(inode), .rpc_message = &msg, .callback_ops = cb, #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) .workqueue = nfsio_workqueue, #endif .flags = RPC_TASK_ASYNC, }; nreq->res.count = nreq->args.count; nreq->header->cred = msg.rpc_cred; nreq->args.context = ctx; task_setup_data.task = &nreq->task; task_setup_data.callback_data = nreq; msg.rpc_argp = &nreq->args; msg.rpc_resp = &nreq->res; NFS_PROTO(inode)->read_setup(nreq, &msg); task = rpc_run_task(&task_setup_data); if (unlikely(IS_ERR(task))) return PTR_ERR(task); rpc_put_task(task); return 0; } #else static int rbio_submit(struct ploop_io * io, struct nfs_read_data * nreq, const struct rpc_call_ops * cb) { struct nfs_open_context *ctx = nfs_file_open_context(io->files.file); struct inode *inode = io->files.inode; nreq->res.count = nreq->args.count; nreq->cred = ctx->cred; nreq->args.context = ctx; rpc_init_task(&nreq->task, NFS_CLIENT(inode), RPC_TASK_ASYNC, cb, nreq); NFS_PROTO(inode)->read_setup(nreq); nreq->task.tk_cookie = (unsigned long) inode; lock_kernel(); rpc_execute(&nreq->task); unlock_kernel(); return 0; } #endif static void nfsio_submit_read(struct ploop_io *io, struct ploop_request * preq, struct bio_list *sbl, iblock_t iblk, unsigned int size) { struct inode *inode = io->files.inode; size_t rsize = NFS_SERVER(inode)->rsize; struct nfs_read_data *nreq = NULL; loff_t pos; unsigned int prev_end; struct bio * b; ploop_prepare_io_request(preq); pos = sbl->head->bi_sector; pos = ((loff_t)iblk << preq->plo->cluster_log) | (pos & ((1<<preq->plo->cluster_log) - 1)); pos <<= 9; prev_end = PAGE_SIZE; for (b = sbl->head; b != NULL; b = b->bi_next) { int bv_idx; for (bv_idx = 0; bv_idx < b->bi_vcnt; bv_idx++) { struct bio_vec * bv = &b->bi_io_vec[bv_idx]; if (nreq && nreq->args.count + bv->bv_len <= rsize) { if (nreq->pages.pagevec[nreq->pages.npages-1] == bv->bv_page && prev_end == bv->bv_offset) { nreq->args.count += bv->bv_len; pos += bv->bv_len; prev_end += bv->bv_len; continue; } if (nreq->pages.npages < MAX_NBIO_PAGES && bv->bv_offset == 0 && prev_end == PAGE_SIZE) { nreq->args.count += bv->bv_len; nreq->pages.pagevec[nreq->pages.npages] = bv->bv_page; nreq->pages.npages++; pos += bv->bv_len; prev_end = bv->bv_offset + bv->bv_len; continue; } } if (nreq) { int err; atomic_inc(&preq->io_count); err = rbio_submit(io, nreq, &nfsio_read_ops); if (err) { PLOOP_REQ_SET_ERROR(preq, err); ploop_complete_io_request(preq); goto out; } } nreq = rbio_init(pos, bv->bv_page, bv->bv_offset, bv->bv_len, preq, inode); if (nreq == NULL) { PLOOP_REQ_SET_ERROR(preq, -ENOMEM); goto out; } pos += bv->bv_len; prev_end = bv->bv_offset + bv->bv_len; } } if (nreq) { int err; atomic_inc(&preq->io_count); err = rbio_submit(io, nreq, &nfsio_read_ops); if (err) { PLOOP_REQ_SET_ERROR(preq, err); ploop_complete_io_request(preq); goto out; } } out: ploop_complete_io_request(preq); } static void nfsio_write_result(struct rpc_task *task, void *calldata) { struct nfs_write_data *data = calldata; struct nfs_writeargs *argp = &data->args; struct nfs_writeres *resp = &data->res; int status; status = NFS_PROTO(data->header->inode)->write_done(task, data); if (status != 0) return; if (task->tk_status >= 0 && resp->count < argp->count) task->tk_status = -EIO; } static void nfsio_write_release(void *calldata) { struct nfs_write_data *nreq = calldata; struct ploop_request *preq = (struct ploop_request *) nreq->header->req; int status = nreq->task.tk_status; if (unlikely(status < 0)) PLOOP_REQ_SET_ERROR(preq, status); if (!preq->error && nreq->res.verf->committed != NFS_FILE_SYNC) { if (!test_and_set_bit(PLOOP_REQ_UNSTABLE, &preq->state)) memcpy(&preq->verf, &nreq->res.verf->verifier, 8); } nfsio_complete_io_request(preq); nfsio_wbio_release(calldata); } static const struct rpc_call_ops nfsio_write_ops = { .rpc_call_done = nfsio_write_result, .rpc_release = nfsio_write_release, }; static struct nfs_write_data * wbio_init(loff_t pos, struct page * page, unsigned int off, unsigned int len, void * priv, struct inode * inode) { struct nfs_write_data * nreq; nreq = nfsio_wbio_alloc(MAX_NBIO_PAGES); if (unlikely(nreq == NULL)) return NULL; nreq->args.offset = pos; nreq->args.pgbase = off; nreq->args.count = len; nreq->pages.pagevec[0] = page; nreq->pages.npages = 1; nreq->header->req = priv; nreq->header->inode = inode; nreq->args.fh = NFS_FH(inode); nreq->args.pages = nreq->pages.pagevec; nreq->args.stable = NFS_UNSTABLE; nreq->res.fattr = &nreq->fattr; nreq->res.verf = &nreq->verf; return nreq; } #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18) static int wbio_submit(struct ploop_io * io, struct nfs_write_data *nreq, const struct rpc_call_ops * cb) { struct nfs_open_context *ctx = nfs_file_open_context(io->files.file); struct inode *inode = io->files.inode; struct rpc_task *task; struct rpc_message msg = { .rpc_cred = ctx->cred, }; struct rpc_task_setup task_setup_data = { .rpc_client = NFS_CLIENT(inode), .rpc_message = &msg, .callback_ops = cb, #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,25) .workqueue = nfsio_workqueue, #endif .flags = RPC_TASK_ASYNC, }; if (verify_bounce(nreq)) return -ENOMEM; nreq->res.count = nreq->args.count; nreq->args.context = ctx; nreq->header->cred = msg.rpc_cred; task_setup_data.task = &nreq->task; task_setup_data.callback_data = nreq; msg.rpc_argp = &nreq->args; msg.rpc_resp = &nreq->res; NFS_PROTO(inode)->write_setup(nreq, &msg); task = rpc_run_task(&task_setup_data); if (unlikely(IS_ERR(task))) return PTR_ERR(task); rpc_put_task(task); return 0; } #else static int wbio_submit(struct ploop_io * io, struct nfs_write_data *nreq, const struct rpc_call_ops * cb) { struct nfs_open_context *ctx = nfs_file_open_context(io->files.file); struct inode *inode = io->files.inode; if (verify_bounce(nreq)) return -ENOMEM; nreq->res.count = nreq->args.count; nreq->args.context = ctx; nreq->cred = ctx->cred; rpc_init_task(&nreq->task, NFS_CLIENT(inode), RPC_TASK_ASYNC, cb, nreq); NFS_PROTO(inode)->write_setup(nreq, NFS_UNSTABLE); nreq->task.tk_priority = RPC_PRIORITY_NORMAL; nreq->task.tk_cookie = (unsigned long) inode; lock_kernel(); rpc_execute(&nreq->task); unlock_kernel(); return 0; } #endif static void nfsio_submit_write(struct ploop_io *io, struct ploop_request * preq, struct bio_list *sbl, iblock_t iblk, unsigned int size) { struct inode *inode = io->files.inode; size_t wsize = NFS_SERVER(inode)->wsize; struct nfs_write_data *nreq = NULL; loff_t pos; struct bio * b; unsigned int prev_end; nfsio_prepare_io_request(preq); pos = sbl->head->bi_sector; pos = ((loff_t)iblk << preq->plo->cluster_log) | (pos & ((1<<preq->plo->cluster_log) - 1)); ploop_prepare_tracker(preq, pos); pos <<= 9; prev_end = PAGE_SIZE; for (b = sbl->head; b != NULL; b = b->bi_next) { int bv_idx; for (bv_idx = 0; bv_idx < b->bi_vcnt; bv_idx++) { struct bio_vec * bv = &b->bi_io_vec[bv_idx]; if (nreq && nreq->args.count + bv->bv_len <= wsize) { if (nreq->pages.pagevec[nreq->pages.npages-1] == bv->bv_page && prev_end == bv->bv_offset) { nreq->args.count += bv->bv_len; pos += bv->bv_len; prev_end += bv->bv_len; continue; } if (nreq->pages.npages < MAX_NBIO_PAGES && bv->bv_offset == 0 && prev_end == PAGE_SIZE) { nreq->args.count += bv->bv_len; nreq->pages.pagevec[nreq->pages.npages] = bv->bv_page; nreq->pages.npages++; pos += bv->bv_len; prev_end = bv->bv_offset + bv->bv_len; continue; } } if (nreq) { int err; atomic_inc(&preq->io_count); err = wbio_submit(io, nreq, &nfsio_write_ops); if (err) { PLOOP_REQ_SET_ERROR(preq, err); nfsio_complete_io_request(preq); goto out; } } nreq = wbio_init(pos, bv->bv_page, bv->bv_offset, bv->bv_len, preq, inode); if (nreq == NULL) { PLOOP_REQ_SET_ERROR(preq, -ENOMEM); goto out; } prev_end = bv->bv_offset + bv->bv_len; pos += bv->bv_len; } } if (nreq) { int err; atomic_inc(&preq->io_count); err = wbio_submit(io, nreq, &nfsio_write_ops); if (err) { PLOOP_REQ_SET_ERROR(preq, err); nfsio_complete_io_request(preq); } } out: nfsio_complete_io_request(preq); } static void nfsio_submit(struct ploop_io *io, struct ploop_request * preq, unsigned long rw, struct bio_list *sbl, iblock_t iblk, unsigned int size) { if (iblk == PLOOP_ZERO_INDEX) iblk = 0; if (rw & (1<<BIO_RW)) nfsio_submit_write(io, preq, sbl, iblk, size); else nfsio_submit_read(io, preq, sbl, iblk, size); } struct bio_list_walk { struct bio * cur; int idx; int bv_off; }; static void nfsio_submit_write_pad(struct ploop_io *io, struct ploop_request * preq, struct bio_list *sbl, iblock_t iblk, unsigned int size) { struct inode *inode = io->files.inode; size_t wsize = NFS_SERVER(inode)->wsize; struct nfs_write_data *nreq = NULL; struct bio_list_walk bw; unsigned prev_end; loff_t pos, end_pos, start, end; /* pos..end_pos is the range which we are going to write */ pos = (loff_t)iblk << (preq->plo->cluster_log + 9); end_pos = pos + (1 << (preq->plo->cluster_log + 9)); /* start..end is data that we have. The rest must be zero padded. */ start = pos + ((sbl->head->bi_sector & ((1<<preq->plo->cluster_log) - 1)) << 9); end = start + (size << 9); nfsio_prepare_io_request(preq); ploop_prepare_tracker(preq, start >> 9); prev_end = PAGE_SIZE; #if 1 /* GCC, shut up! */ bw.cur = sbl->head; bw.idx = 0; bw.bv_off = 0; BUG_ON(bw.cur->bi_io_vec[0].bv_len & 511); #endif while (pos < end_pos) { struct page * page; unsigned int poff, plen; if (pos < start) { page = ZERO_PAGE(0); poff = 0; plen = start - pos; if (plen > PAGE_SIZE) plen = PAGE_SIZE; } else if (pos >= end) { page = ZERO_PAGE(0); poff = 0; plen = end_pos - pos; if (plen > PAGE_SIZE) plen = PAGE_SIZE; } else { /* pos >= start && pos < end */ struct bio_vec * bv; if (pos == start) { bw.cur = sbl->head; bw.idx = 0; bw.bv_off = 0; BUG_ON(bw.cur->bi_io_vec[0].bv_len & 511); } bv = bw.cur->bi_io_vec + bw.idx; if (bw.bv_off >= bv->bv_len) { bw.idx++; bv++; bw.bv_off = 0; if (bw.idx >= bw.cur->bi_vcnt) { bw.cur = bw.cur->bi_next; bw.idx = 0; bw.bv_off = 0; bv = bw.cur->bi_io_vec; } BUG_ON(bv->bv_len & 511); } page = bv->bv_page; poff = bv->bv_offset + bw.bv_off; plen = bv->bv_len - bw.bv_off; } if (nreq && nreq->args.count + plen <= wsize) { if (nreq->pages.pagevec[nreq->pages.npages-1] == page && prev_end == poff) { nreq->args.count += plen; pos += plen; bw.bv_off += plen; prev_end += plen; continue; } if (nreq->pages.npages < MAX_NBIO_PAGES && poff == 0 && prev_end == PAGE_SIZE) { nreq->args.count += plen; nreq->pages.pagevec[nreq->pages.npages] = page; nreq->pages.npages++; pos += plen; bw.bv_off += plen; prev_end = poff + plen; continue; } } if (nreq) { int err; atomic_inc(&preq->io_count); err = wbio_submit(io, nreq, &nfsio_write_ops); if (err) { PLOOP_REQ_SET_ERROR(preq, err); nfsio_complete_io_request(preq); goto out; } } nreq = wbio_init(pos, page, poff, plen, preq, inode); if (nreq == NULL) { PLOOP_REQ_SET_ERROR(preq, -ENOMEM); goto out; } prev_end = poff + plen; pos += plen; bw.bv_off += plen; } if (nreq) { int err; atomic_inc(&preq->io_count); err = wbio_submit(io, nreq, &nfsio_write_ops); if (err) { PLOOP_REQ_SET_ERROR(preq, err); nfsio_complete_io_request(preq); } } out: nfsio_complete_io_request(preq); } static void nfsio_submit_alloc(struct ploop_io *io, struct ploop_request * preq, struct bio_list * sbl, unsigned int size) { iblock_t iblk = io->alloc_head++; if (!(io->files.file->f_mode & FMODE_WRITE)) { PLOOP_FAIL_REQUEST(preq, -EBADF); return; } preq->iblock = iblk; preq->eng_state = PLOOP_E_DATA_WBI; nfsio_submit_write_pad(io, preq, sbl, iblk, size); } static void nfsio_destroy(struct ploop_io * io) { if (io->fsync_thread) { kthread_stop(io->fsync_thread); io->fsync_thread = NULL; } if (io->files.file) { struct file * file = io->files.file; mutex_lock(&io->plo->sysfs_mutex); io->files.file = NULL; if (io->files.mapping) (void)invalidate_inode_pages2(io->files.mapping); mutex_unlock(&io->plo->sysfs_mutex); fput(file); } } static int nfsio_sync(struct ploop_io * io) { return 0; } static int nfsio_stop(struct ploop_io * io) { return 0; } static int nfsio_init(struct ploop_io * io) { INIT_LIST_HEAD(&io->fsync_queue); init_waitqueue_head(&io->fsync_waitq); return 0; }