int __send_faf_file_desc(struct rpc_desc *desc, struct file *file) { int r, fdesc_size; void *fdesc; BUG_ON(!file->f_objid); BUG_ON(!(file->f_flags & (O_FAF_SRV|O_FAF_CLT))); r = get_faf_file_krg_desc(file, &fdesc, &fdesc_size); if (r) goto out; r = rpc_pack_type(desc, file->f_objid); if (r) goto out_free_fdesc; r = rpc_pack_type(desc, fdesc_size); if (r) goto out_free_fdesc; r = rpc_pack(desc, 0, fdesc, fdesc_size); if (r) goto out_free_fdesc; out_free_fdesc: kfree(fdesc); out: return r; }
static void handle_faf_poll_wait(struct rpc_desc *desc, void *_msg, size_t size) { struct faf_poll_wait_msg *msg = _msg; struct file *file; unsigned int revents; int err, res = 0; if (msg->wait) { res = faf_polled_fd_add(desc->client, msg->server_fd, msg->objid); err = rpc_pack_type(desc, res); if (err) goto err; } file = fget(msg->server_fd); BUG_ON(!file); revents = file->f_op->poll(file, NULL); fput(file); err = rpc_pack_type(desc, revents); if (err) goto err; return; err: if (msg->wait && !res) faf_polled_fd_remove(desc->client, msg->server_fd, msg->objid); rpc_cancel(desc); }
static int do_nodes_remove(struct hotplug_context *ctx) { struct rpc_desc *desc; krgnodemask_t nodes; kerrighed_node_t node; char *page; int ret; ret = hotplug_start_request(ctx); if (ret) return ret; ret = check_remove_req(ctx); if (ret) goto err_finish; ret = -ENOMEM; page = (char *)__get_free_page(GFP_KERNEL); if (!page) goto err_finish; ret = krgnodelist_scnprintf(page, PAGE_SIZE, ctx->node_set.v); BUG_ON(ret >= PAGE_SIZE); printk("kerrighed: Removing nodes %s ...\n", page); free_page((unsigned long)page); ret = -ENOMEM; krgnodes_copy(nodes, krgnode_online_map); desc = rpc_begin_m(NODE_REMOVE, ctx->ns->rpc_comm, &nodes); if (!desc) goto err_warning; ret = rpc_pack_type(desc, ctx->node_set); if (ret) { rpc_end(desc, 0); goto err_warning; } ret = 0; for_each_krgnode_mask(node, nodes) rpc_unpack_type_from(desc, node, ret); hotplug_finish_request(ctx); rpc_pack_type(desc, ret); rpc_end(desc, 0); printk("kerrighed: Removing nodes succeeded.\n"); out: return ret; err_warning: printk(KERN_ERR "kerrighed: Removing nodes failed! err=%d\n", ret); err_finish: hotplug_finish_request(ctx); goto out; }
/** Export an MM struct * @author Renaud Lottiaux * * @param buffer Buffer to export object data in. * @param obj_entry Object entry of the object to export. */ int mm_export_object (struct rpc_desc *desc, struct kddm_set *set, struct kddm_obj *obj_entry, objid_t objid, int flags) { struct mm_struct *mm; krgsyms_val_t unmap_id, get_unmap_id; mm = obj_entry->object; krgnode_set (desc->client, mm->copyset); rpc_pack(desc, 0, &mm->mm_id, sizeof(unique_id_t)); rpc_pack(desc, 0, &mm->anon_vma_kddm_id, sizeof(unique_id_t)); rpc_pack(desc, 0, &mm->context.vdso, sizeof(void*)); rpc_pack(desc, 0, &mm->copyset, sizeof(krgnodemask_t)); get_unmap_id = krgsyms_export(mm->get_unmapped_area); BUG_ON(mm->get_unmapped_area && get_unmap_id == KRGSYMS_UNDEF); rpc_pack_type(desc, get_unmap_id); unmap_id = krgsyms_export(mm->unmap_area); BUG_ON(mm->unmap_area && unmap_id == KRGSYMS_UNDEF); rpc_pack_type(desc, unmap_id); return 0; }
/** Handler for doing an FSTAT in a FAF open file. * @author Renaud Lottiaux * * @param from Node sending the request * @param msgIn Request message */ void handle_faf_fstat (struct rpc_desc* desc, void *msgIn, size_t size) { struct kstat statbuf; struct faf_stat_msg *msg = msgIn; long r; r = vfs_fstat (msg->server_fd, &statbuf); rpc_pack_type(desc, r); rpc_pack_type(desc, statbuf); }
/** Handler for seeking in a FAF open file. * @author Renaud Lottiaux * * @param from Node sending the request * @param msgIn Request message */ void handle_faf_llseek (struct rpc_desc* desc, void *msgIn, size_t size) { struct faf_llseek_msg *msg = msgIn; long r = -EINVAL; loff_t result; r = sys_llseek (msg->server_fd, msg->offset_high, msg->offset_low, &result, msg->origin); rpc_pack_type(desc, r); rpc_pack_type(desc, result); }
/** Handler for locking in a FAF open file. * @author Renaud Lottiaux * * @param from Node sending the request * @param msgIn Request message */ void handle_faf_flock(struct rpc_desc *desc, void *msgIn, size_t size) { struct faf_ctl_msg *msg = msgIn; const struct cred *old_cred; long r = -EINVAL; int err; old_cred = unpack_override_creds(desc); if (IS_ERR(old_cred)) goto cancel; r = remote_sleep_prepare(desc); if (r) { revert_creds(old_cred); goto cancel; } r = sys_flock (msg->server_fd, msg->cmd); remote_sleep_finish(); revert_creds(old_cred); err = rpc_pack_type(desc, r); if (err) goto cancel; return; cancel: rpc_cancel(desc); }
static int handle_get_pid_cap(struct rpc_desc *desc, void *_msg, size_t size) { struct pid *pid; kernel_krg_cap_t cap; const struct cred *old_cred; int ret; pid = krg_handle_remote_syscall_begin(desc, _msg, size, NULL, &old_cred); if (IS_ERR(pid)) { ret = PTR_ERR(pid); goto out; } ret = krg_get_cap(pid_task(pid, PIDTYPE_PID), &cap); if (ret) goto out_end; ret = rpc_pack_type(desc, cap); if (ret) goto err_cancel; out_end: krg_handle_remote_syscall_end(pid, old_cred); out: return ret; err_cancel: rpc_cancel(desc); goto out_end; }
void handle_faf_sendmsg(struct rpc_desc *desc, void *msgIn, size_t size) { struct faf_sendmsg_msg *msg = msgIn; ssize_t r; int err; struct msghdr msghdr; err = recv_msghdr(desc, &msghdr, msg->total_len, 0); if (err) { rpc_cancel(desc); return; } err = remote_sleep_prepare(desc); if (err) goto cancel; r = sys_sendmsg (msg->server_fd, &msghdr, msg->flags); remote_sleep_finish(); err = rpc_pack_type(desc, r); if (err) goto cancel; out_free: free_msghdr(&msghdr); return; cancel: rpc_cancel(desc); goto out_free; }
static void do_local_node_remove(struct rpc_desc *desc, struct hotplug_context *ctx) { struct rpc_communicator *comm = ctx->ns->rpc_comm; krgnodemask_t prev_online, new_online; int ret; SET_KERRIGHED_NODE_FLAGS(KRGFLAGS_STOPPING); printk("do_local_node_remove\n"); krgnodes_copy(prev_online, krgnode_online_map); krgnodes_andnot(new_online, krgnode_online_map, ctx->node_set.v); atomic_set(&nr_to_wait, krgnodes_weight(new_online)); printk("...notify local\n"); hotplug_remove_notify(ctx, HOTPLUG_NOTIFY_REMOVE_LOCAL); krgnodes_copy(new_online, krgnode_online_map); printk("...notify_distant\n"); hotplug_remove_notify(ctx, HOTPLUG_NOTIFY_REMOVE_DISTANT); printk("...confirm\n"); rpc_sync_m(NODE_REMOVE_CONFIRM, comm, &new_online, &ctx->node_set, sizeof(ctx->node_set)); printk("...wait ack\n"); wait_event(all_removed_wqh, atomic_read(&nr_to_wait) == 0); rpc_disable_all(); rpc_enable(HOTPLUG_FINISH_REQ); ret = 0; rpc_pack_type(desc, ret); rpc_unpack_type(desc, ret); rpc_disable(HOTPLUG_FINISH_REQ); CLEAR_KERRIGHED_NODE_FLAGS(KRGFLAGS_RUNNING); CLEAR_KERRIGHED_CLUSTER_FLAGS(KRGFLAGS_RUNNING); clusters_status[kerrighed_subsession_id] = CLUSTER_UNDEF; down_write(&kerrighed_init_sem); hooks_stop(); up_write(&kerrighed_init_sem); rpc_close_mask(comm, &prev_online); rpc_communicator_put(comm); ctx->ns->rpc_comm = NULL; CLEAR_KERRIGHED_NODE_FLAGS(KRGFLAGS_STOPPING); kerrighed_subsession_id = -1; rpc_enable(CLUSTER_START); }
/* * @author Pascal Gallard */ static int pid_export_object(struct rpc_desc *desc, struct kddm_set *set, struct kddm_obj *obj_entry, objid_t objid, int flags) { struct pid_kddm_object *obj = obj_entry->object; return rpc_pack_type(desc, obj->node_count); }
/** Handler for seeking in a FAF open file. * @author Renaud Lottiaux * * @param from Node sending the request * @param msgIn Request message */ void handle_faf_lseek (struct rpc_desc* desc, void *msgIn, size_t size) { struct faf_seek_msg *msg = msgIn; off_t r = -EINVAL; r = sys_lseek (msg->server_fd, msg->offset, msg->origin); rpc_pack_type(desc, r); }
/** Handler for doing an FCNTL64 in a FAF open file. * @author Renaud Lottiaux * * @param from Node sending the request * @param msgIn Request message */ void handle_faf_fcntl64 (struct rpc_desc* desc, void *msgIn, size_t size) { struct faf_ctl_msg *msg = msgIn; const struct cred *old_cred; unsigned long arg; long r; int err; if (msg->cmd == F_GETLK64 || msg->cmd == F_SETLK64 || msg->cmd == F_SETLKW64) arg = (unsigned long) &msg->flock64; else arg = msg->arg; old_cred = unpack_override_creds(desc); if (IS_ERR(old_cred)) goto cancel; err = remote_sleep_prepare(desc); if (err) { revert_creds(old_cred); goto cancel; } r = sys_fcntl64 (msg->server_fd, msg->cmd, arg); remote_sleep_finish(); revert_creds(old_cred); err = rpc_pack_type(desc, r); if (unlikely(err)) goto cancel; if (!r && msg->cmd == F_GETLK64) { err = rpc_pack_type(desc, msg->flock64); if (unlikely(err)) goto cancel; } return; cancel: rpc_cancel(desc); }
int remote_sleep_prepare(struct rpc_desc *desc) { int dummy, err; current->sighand->action[SIGINT - 1].sa.sa_handler = SIG_DFL; err = rpc_pack_type(desc, dummy); if (err) ignore_signals(current); return err; }
/** Handler for doing an FSTATFS in a FAF open file. * @author Matthieu Fertré * * @param from Node sending the request * @param msgIn Request message */ static void handle_faf_fstatfs(struct rpc_desc* desc, void *msgIn, size_t size) { struct statfs statbuf; struct faf_statfs_msg *msg = msgIn; long r; int err_rpc; r = sys_fstatfs(msg->server_fd, &statbuf); err_rpc = rpc_pack_type(desc, r); if (err_rpc) goto err_rpc; if (!r) err_rpc = rpc_pack_type(desc, statbuf); err_rpc: if (err_rpc) rpc_cancel(desc); }
/* cluster receive the confirmation about the remove operation */ static void handle_node_remove_confirm(struct rpc_desc *desc, void *data, size_t size) { int dummy; BUG_ON(desc->client == kerrighed_node_id); hotplug_remove_notify((void*)&desc->client, HOTPLUG_NOTIFY_REMOVE_ACK); if (rpc_pack_type(desc, dummy)) rpc_cancel(desc); if (atomic_dec_and_test(&nr_to_wait)) wake_up(&all_removed_wqh); printk("Kerrighed: node %d removed\n", desc->client); }
long get_appid_from_pid(pid_t pid) { struct rpc_desc *desc; kerrighed_node_t n = KERRIGHED_NODE_ID_NONE; struct getappid_request_msg msg; long app_id; int err = 0; /* lock the task to be sure it does not exit */ n = krg_lock_pid_location(pid); if (n == KERRIGHED_NODE_ID_NONE) return -ESRCH; /* the task is local */ if (n == kerrighed_node_id) { app_id = __get_appid_from_local_pid(pid); if (app_id < 0) err = app_id; goto out_unlock; } err = -ENOMEM; msg.requester = kerrighed_node_id; msg.pid = pid; desc = rpc_begin(APP_REMOTE_CHKPT, n); if (!desc) goto out_unlock; err = rpc_pack_type(desc, msg); if (err) goto err; err = pack_creds(desc, current_cred()); if (err) goto err; err = rpc_unpack_type(desc, app_id); if (err) goto err; out_end: rpc_end(desc, 0); out_unlock: krg_unlock_pid_location(pid); if (err) return err; return app_id; err: rpc_cancel(desc); goto out_end; }
static void handle_faf_readv(struct rpc_desc *desc, void *__msg, size_t size) { struct faf_rw_msg *msg = __msg; struct faf_rw_ret ret; struct file *file; struct iovec *iov; int iovcnt, err; err = alloc_iov(&iov, &iovcnt, msg->count); if (err) { ret.ret = err; iov = NULL; } err = remote_sleep_prepare(desc); if (err) goto cancel; ret.pos = msg->pos; if (iov) { file = fget(msg->server_fd); ret.ret = vfs_readv(file, iov, iovcnt, &ret.pos); fput(file); } remote_sleep_finish(); err = rpc_pack_type(desc, ret); if (err) goto cancel; if (ret.ret <= 0) goto out_free; err = send_iov(desc, iov, iovcnt, ret.ret, 0); if (err) goto cancel; out_free: if (iov) free_iov(iov, iovcnt); return; cancel: rpc_cancel(desc); goto out_free; }
static void do_other_node_remove(struct rpc_desc *desc, struct hotplug_context *ctx) { int ret; printk("do_other_node_remove\n"); atomic_set(&nr_to_wait, krgnodes_weight(ctx->node_set.v)); hotplug_remove_notify(ctx, HOTPLUG_NOTIFY_REMOVE_ADVERT); rpc_async_m(NODE_REMOVE_ACK, ctx->ns->rpc_comm, &ctx->node_set.v, NULL, 0); wait_event(all_removed_wqh, atomic_read(&nr_to_wait) == 0); ret = 0; rpc_pack_type(desc, ret); rpc_unpack_type(desc, ret); rpc_close_mask(ctx->ns->rpc_comm, &ctx->node_set.v); }
/** Handler for doing an IOCTL in a FAF open file. * @author Renaud Lottiaux * * @param from Node sending the request * @param msgIn Request message */ void handle_faf_ioctl(struct rpc_desc *desc, void *msgIn, size_t size) { struct faf_ctl_msg *msg = msgIn; struct prev_root prev_root; const struct cred *old_cred; long r; int err; err = unpack_context(desc, &prev_root, &old_cred); if (err) { rpc_cancel(desc); return; } err = remote_sleep_prepare(desc); if (err) goto out_err; err = prepare_ruaccess(desc); if (err) goto out_sleep_finish; r = sys_ioctl(msg->server_fd, msg->cmd, msg->arg); err = cleanup_ruaccess(desc); if (err) goto out_sleep_finish; err = rpc_pack_type(desc, r); out_sleep_finish: remote_sleep_finish(); if (err) goto out_err; out: restore_context(&prev_root, old_cred); return; out_err: rpc_cancel(desc); goto out; }
int handle_faf_getpeername (struct rpc_desc* desc, void *msgIn, size_t size) { struct faf_bind_msg *msg = msgIn; struct prev_root prev_root; int r; unpack_root(desc, &prev_root); r = sys_getpeername(msg->server_fd, (struct sockaddr *)&msg->sa, &msg->addrlen); rpc_pack_type(desc, msg->addrlen); rpc_pack(desc, 0, &msg->sa, msg->addrlen); chroot_to_prev_root(&prev_root); return r; }
/* * @author Pascal Gallard */ static int task_export_object(struct rpc_desc *desc, struct kddm_set *set, struct kddm_obj *obj_entry, objid_t objid, int flags) { struct task_kddm_object *src = obj_entry->object; struct task_struct *tsk; read_lock(&tasklist_lock); tsk = src->task; if (likely(tsk)) { task_lock(tsk); task_update_object(src); task_unlock(tsk); } read_unlock(&tasklist_lock); return rpc_pack_type(desc, *src); }
void handle_faf_setsockopt (struct rpc_desc *desc, void *msgIn, size_t size) { struct faf_setsockopt_msg *msg = msgIn; struct prev_root prev_root; const struct cred *old_cred; int r, err; err = unpack_context(desc, &prev_root, &old_cred); if (err) { rpc_cancel(desc); return; } err = prepare_ruaccess(desc); if (err) goto out_err; r = sys_setsockopt(msg->server_fd, msg->level, msg->optname, msg->optval, msg->optlen); err = cleanup_ruaccess(desc); if (err) goto out_err; err = rpc_pack_type(desc, r); if (err) goto out_err; exit: restore_context(&prev_root, old_cred); return; out_err: rpc_cancel(desc); if (err > 0) err = -ENOMEM; r = err; goto exit; }
static void handle_get_appid_from_pid(struct rpc_desc *desc, void *_msg, size_t size) { struct getappid_request_msg *msg = _msg; long app_id; const struct cred *old_cred; int err; old_cred = unpack_override_creds(desc); if (IS_ERR(old_cred)) { err = PTR_ERR(old_cred); goto out; } app_id = __get_appid_from_local_pid(msg->pid); revert_creds(old_cred); err = rpc_pack_type(desc, app_id); out: if (err) rpc_cancel(desc); }
int cluster_barrier(struct cluster_barrier *barrier, krgnodemask_t *nodes, kerrighed_node_t master) { struct cluster_barrier_core *core_bar; struct cluster_barrier_id id; struct rpc_desc *desc; int err = 0; BUG_ON (!__krgnode_isset(kerrighed_node_id, nodes)); BUG_ON (!__krgnode_isset(master, nodes)); spin_lock(&barrier->lock); barrier->id.toggle = (barrier->id.toggle + 1) % 2; id = barrier->id; core_bar = &barrier->core[id.toggle]; if (core_bar->in_barrier) err = -EBUSY; core_bar->in_barrier = 1; spin_unlock(&barrier->lock); if (err) return err; desc = rpc_begin(RPC_ENTER_BARRIER, master); rpc_pack_type (desc, id); rpc_pack(desc, 0, nodes, sizeof(krgnodemask_t)); rpc_end(desc, 0); /* Wait for the barrier to complete */ wait_event (core_bar->waiting_tsk, (core_bar->in_barrier == 0)); return 0; }
void handle_faf_connect(struct rpc_desc *desc, void *msgIn, size_t size) { struct faf_bind_msg *msg = msgIn; struct prev_root prev_root; const struct cred *old_cred; int r, err; r = unpack_context(desc, &prev_root, &old_cred); if (r) { rpc_cancel(desc); return; } r = remote_sleep_prepare(desc); if (r) goto cancel; r = sys_connect(msg->server_fd, (struct sockaddr *)&msg->sa, msg->addrlen); remote_sleep_finish(); err = rpc_pack_type(desc, r); if (err) goto cancel; out: restore_context(&prev_root, old_cred); return; cancel: rpc_cancel(desc); goto out; }
void handle_faf_accept (struct rpc_desc *desc, void *msgIn, size_t size) { struct faf_bind_msg *msg = msgIn; int err, r; struct file *file; r = remote_sleep_prepare(desc); if (r) goto err_cancel; r = sys_accept(msg->server_fd, (struct sockaddr *)&msg->sa, &msg->addrlen); remote_sleep_finish(); err = rpc_pack_type(desc, r); if (err) goto err_close_file; if (r < 0) return; file = fcheck_files(current->files, r); if (!file->f_objid) { err = create_kddm_file_object(file); if (err) goto err_close_file; } file->f_flags |= O_FAF_SRV; file->f_faf_srv_index = r; /* Increment the DVFS count for the client node */ get_dvfs_file(r, file->f_objid); err = rpc_pack_type(desc, msg->addrlen); if (err) goto err_close_faf_file; err = rpc_pack(desc, 0, &msg->sa, msg->addrlen); if (err) goto err_close_faf_file; err = __send_faf_file_desc(desc, file); if (err) goto err_close_faf_file; err = rpc_unpack_type(desc, r); if (err) goto err_close_faf_file; out: return; err_cancel: rpc_cancel(desc); goto out; err_close_faf_file: /* The client couldn't setup a FAF client file. */ put_dvfs_file(file->f_faf_srv_index, file); check_close_faf_srv_file(file); goto err_cancel; err_close_file: if (r >= 0) sys_close(r); goto err_cancel; }
/** Handler for d_path in a FAF open file. * @author Renaud Lottiaux * * @param from Node sending the request * @param msgIn Request message */ void handle_faf_d_path (struct rpc_desc* desc, void *msgIn, size_t size) { struct faf_d_path_msg *msg = msgIn; char *buff, *file_name = NULL; struct file *file; struct prev_root prev_root; const struct cred *old_cred; bool deleted = false; int len; int err; old_cred = unpack_override_creds(desc); if (IS_ERR(old_cred)) { rpc_cancel(desc); return; } err = unpack_root(desc, &prev_root); if (err) { revert_creds(old_cred); rpc_cancel(desc); return; } buff = kmalloc (msg->count, GFP_KERNEL); file = fcheck_files (current->files, msg->server_fd); /* Remote caller holds a reference so it can't disappear. */ BUG_ON(!file); if (msg->deleted) file_name = d_path_check(&file->f_path, buff, msg->count, &deleted); else file_name = d_path(&file->f_path, buff, msg->count); if (IS_ERR(file_name)) len = PTR_ERR(file_name); else len = strlen(file_name) + 1; err = rpc_pack_type(desc, len); if (err) goto err_cancel; if (len >= 0) { err = rpc_pack(desc, 0, file_name, len); if (err) goto err_cancel; if (msg->deleted) { err = rpc_pack_type(desc, deleted); if (err) goto err_cancel; } } out: kfree (buff); chroot_to_prev_root(&prev_root); revert_creds(old_cred); return; err_cancel: rpc_cancel(desc); goto out; }
/** Handler for reading in a FAF open file. * @author Renaud Lottiaux, Matthieu Fertré * * @param from Node sending the request * @param msgIn Request message */ void handle_faf_read(struct rpc_desc* desc, void *msgIn, size_t size) { struct faf_rw_msg *msg = msgIn; struct file *file = NULL; char *buf = NULL; long buf_size = PAGE_SIZE; ssize_t to_read, r; loff_t fpos; int err; err = remote_sleep_prepare(desc); if (err) { rpc_cancel(desc); return; } to_read = msg->count; fpos = msg->pos; r = -ENOMEM; buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!buf) goto error; file = fget(msg->server_fd); while (to_read > 0) { if (to_read < PAGE_SIZE) buf_size = to_read; r = vfs_read(file, buf, buf_size, &fpos); if (r > 0) { err = rpc_pack_type(desc, r); if (err) goto cancel; err = rpc_pack(desc, 0, buf, r); if (err) goto cancel; } /* * Check if we have reach the end of the file * or if there is an error */ if (r < buf_size) break; to_read -= r; } error: /* * Pack the end of transmission mark (0) * or the error returned by vfs_read() */ if (r > 0) r = 0; err = rpc_pack_type(desc, r); if (err) goto cancel; /* send the updated file position */ err = rpc_pack_type(desc, fpos); if (err) goto cancel; out: if (buf) kfree(buf); if (file) fput(file); remote_sleep_finish(); return; cancel: rpc_cancel(desc); goto out; }
/** Handler for writing in a FAF open file. * @author Renaud Lottiaux, Matthieu Fertré * * @param from Node sending the request * @param msgIn Request message */ void handle_faf_write(struct rpc_desc* desc, void *msgIn, size_t size) { struct faf_rw_msg *msg = msgIn; struct file *file = NULL; long to_recv; char *buf = NULL; ssize_t buf_size = PAGE_SIZE; ssize_t r, nr_received = -ENOMEM; loff_t fpos; int err; r = remote_sleep_prepare(desc); if (r) { rpc_cancel(desc); return; } to_recv = msg->count; fpos = msg->pos; buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!buf) goto error; nr_received = 0; file = fget(msg->server_fd); while (to_recv > 0) { err = rpc_unpack_type(desc, buf_size); if (err) goto cancel; /* copy_from_user has failed on the other side */ if (buf_size < 0) { nr_received = buf_size; break; } err = rpc_unpack(desc, 0, buf, buf_size); if (err) goto cancel; r = vfs_write(file, buf, buf_size, &fpos); /* The last write failed. Break the write sequence */ if (r < 0) { nr_received = r; break; } nr_received += r; to_recv -= buf_size; } error: err = rpc_pack_type(desc, nr_received); if (err) goto cancel; /* send the updated file position */ err = rpc_pack_type(desc, fpos); if (err) goto cancel; out: if (buf) kfree(buf); if (file) fput(file); remote_sleep_finish(); return; cancel: rpc_cancel(desc); goto out; }