/* FUSE: Filesystem in Userspace Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> This program can be distributed under the terms of the GNU GPL. See the file COPYING.*/ #include "fuse_i.h" #include <linux/init.h>#include <linux/module.h>#include <linux/poll.h>#include <linux/uio.h>#include <linux/miscdevice.h>#include <linux/pagemap.h>#include <linux/file.h>#include <linux/slab.h> MODULE_ALIAS_MISCDEV(FUSE_MINOR); static kmem_cache_t *fuse_req_cachep; static struct fuse_conn *fuse_get_conn(struct file *file){ /* * Lockless access is OK, because file->private data is set * once during mount and is valid until the file is released. */ return file->private_data;} static void fuse_request_init(struct fuse_req *req){ memset(req, 0, sizeof(*req)); INIT_LIST_HEAD(&req->list); init_waitqueue_head(&req->waitq); atomic_set(&req->count, 1);} struct fuse_req *fuse_request_alloc(void){ struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, SLAB_KERNEL); if (req) fuse_request_init(req); return req;} void fuse_request_free(struct fuse_req *req){ kmem_cache_free(fuse_req_cachep, req);} static void block_sigs(sigset_t *oldset){ sigset_t mask; siginitsetinv(&mask, sigmask(SIGKILL)); sigprocmask(SIG_BLOCK, &mask, oldset);} static void restore_sigs(sigset_t *oldset){ sigprocmask(SIG_SETMASK, oldset, NULL);} /* * Reset request, so that it can be reused * * The caller must be _very_ careful to make sure, that it is holding * the only reference to req */void fuse_reset_request(struct fuse_req *req){ BUG_ON(atomic_read(&req->count) != 1); fuse_request_init(req);} static void __fuse_get_request(struct fuse_req *req){ atomic_inc(&req->count);} /* Must be called with > 1 refcount */static void __fuse_put_request(struct fuse_req *req){ BUG_ON(atomic_read(&req->count) < 2); atomic_dec(&req->count);} struct fuse_req *fuse_get_req(struct fuse_conn *fc){ struct fuse_req *req; sigset_t oldset; int intr; int err; atomic_inc(&fc->num_waiting); block_sigs(&oldset); intr = wait_event_interruptible(fc->blocked_waitq, !fc->blocked); restore_sigs(&oldset); err = -EINTR; if (intr) goto out; req = fuse_request_alloc(); err = -ENOMEM; if (!req) goto out; req->in.h.uid = current->fsuid; req->in.h.gid = current->fsgid; req->in.h.pid = current->pid; req->waiting = 1; return req; out: atomic_dec(&fc->num_waiting); return ERR_PTR(err);} void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req){ if (atomic_dec_and_test(&req->count)) { if (req->waiting) atomic_dec(&fc->num_waiting); fuse_request_free(req); }} /* * Called with sbput_sem held for read (request_end) or write * (fuse_put_super). By the time fuse_put_super() is finished, all * inodes belonging to background requests must be released, so the * iputs have to be done within the locked region. */void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req){ iput(req->inode); iput(req->inode2); spin_lock(&fc->lock); list_del(&req->bg_entry); if (fc->num_background == FUSE_MAX_BACKGROUND) { fc->blocked = 0; wake_up_all(&fc->blocked_waitq); } fc->num_background--; spin_unlock(&fc->lock);} /* * This function is called when a request is finished. Either a reply * has arrived or it was interrupted (and not yet sent) or some error * occurred during communication with userspace, or the device file * was closed. In case of a background request the reference to the * stored objects are released. The requester thread is woken up (if * still waiting), the 'end' callback is called if given, else the * reference to the request is released * * Releasing extra reference for foreground requests must be done * within the same locked region as setting state to finished. This * is because fuse_reset_request() may be called after request is * finished and it must be the sole possessor. If request is * interrupted and put in the background, it will return with an error * and hence never be reset and reused. * * Called with fc->lock, unlocks it */static void request_end(struct fuse_conn *fc, struct fuse_req *req){ list_del(&req->list); req->state = FUSE_REQ_FINISHED; if (!req->background) { spin_unlock(&fc->lock); wake_up(&req->waitq); fuse_put_request(fc, req); } else { void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; req->end = NULL; spin_unlock(&fc->lock); down_read(&fc->sbput_sem); if (fc->mounted) fuse_release_background(fc, req); up_read(&fc->sbput_sem); /* fput must go outside sbput_sem, otherwise it can deadlock */ if (req->file) fput(req->file); if (end) end(fc, req); else fuse_put_request(fc, req); }} /* * Unfortunately request interruption not just solves the deadlock * problem, it causes problems too. These stem from the fact, that an * interrupted request is continued to be processed in userspace, * while all the locks and object references (inode and file) held * during the operation are released. * * To release the locks is exactly why there's a need to interrupt the * request, so there's not a lot that can be done about this, except * introduce additional locking in userspace. * * More important is to keep inode and file references until userspace * has replied, otherwise FORGET and RELEASE could be sent while the * inode/file is still used by the filesystem. * * For this reason the concept of "background" request is introduced. * An interrupted request is backgrounded if it has been already sent * to userspace. Backgrounding involves getting an extra reference to * inode(s) or file used in the request, and adding the request to * fc->background list. When a reply is received for a background * request, the object references are released, and the request is * removed from the list. If the filesystem is unmounted while there * are still background requests, the list is walked and references * are released as if a reply was received. * * There's one more use for a background request. The RELEASE message is * always sent as background, since it doesn't return an error or * data. */static void background_request(struct fuse_conn *fc, struct fuse_req *req){ req->background = 1; list_add(&req->bg_entry, &fc->background); fc->num_background++; if (fc->num_background == FUSE_MAX_BACKGROUND) fc->blocked = 1; if (req->inode) req->inode = igrab(req->inode); if (req->inode2) req->inode2 = igrab(req->inode2); if (req->file) get_file(req->file);} /* Called with fc->lock held. Releases, and then reacquires it. */static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req){ sigset_t oldset; spin_unlock(&fc->lock); block_sigs(&oldset); wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED); restore_sigs(&oldset); spin_lock(&fc->lock); if (req->state == FUSE_REQ_FINISHED && !req->interrupted) return; if (!req->interrupted) { req->out.h.error = -EINTR; req->interrupted = 1; } if (req->locked) { /* This is uninterruptible sleep, because data is being copied to/from the buffers of req. During locked state, there mustn't be any filesystem operation (e.g. page fault), since that could lead to deadlock */ spin_unlock(&fc->lock); wait_event(req->waitq, !req->locked); spin_lock(&fc->lock); } if (req->state == FUSE_REQ_PENDING) { list_del(&req->list); __fuse_put_request(req); } else if (req->state == FUSE_REQ_SENT) background_request(fc, req);} static unsigned len_args(unsigned numargs, struct fuse_arg *args){ unsigned nbytes = 0; unsigned i; for (i = 0; i < numargs; i++) nbytes += args[i].size; return nbytes;} static void queue_request(struct fuse_conn *fc, struct fuse_req *req){ fc->reqctr++; /* zero is special */ if (fc->reqctr == 0) fc->reqctr = 1; req->in.h.unique = fc->reqctr; req->in.h.len = sizeof(struct fuse_in_header) + len_args(req->in.numargs, (struct fuse_arg *) req->in.args); list_add_tail(&req->list, &fc->pending); req->state = FUSE_REQ_PENDING; if (!req->waiting) { req->waiting = 1; atomic_inc(&fc->num_waiting); } wake_up(&fc->waitq); kill_fasync(&fc->fasync, SIGIO, POLL_IN);} /* * This can only be interrupted by a SIGKILL */void request_send(struct fuse_conn *fc, struct fuse_req *req){ req->isreply = 1; spin_lock(&fc->lock); if (!fc->connected) req->out.h.error = -ENOTCONN; else if (fc->conn_error) req->out.h.error = -ECONNREFUSED; else { queue_request(fc, req); /* acquire extra reference, since request is still needed after request_end() */ __fuse_get_request(req); request_wait_answer(fc, req); } spin_unlock(&fc->lock);} static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req){ spin_lock(&fc->lock); background_request(fc, req); if (fc->connected) { queue_request(fc, req); spin_unlock(&fc->lock); } else { req->out.h.error = -ENOTCONN; request_end(fc, req); }} void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req){ req->isreply = 0; request_send_nowait(fc, req);} void request_send_background(struct fuse_conn *fc, struct fuse_req *req){ req->isreply = 1; request_send_nowait(fc, req);} /* * Lock the request. Up to the next unlock_request() there mustn't be * anything that could cause a page-fault. If the request was already * interrupted bail out. */static int lock_request(struct fuse_conn *fc, struct fuse_req *req){ int err = 0; if (req) { spin_lock(&fc->lock); if (req->interrupted) err = -ENOENT; else req->locked = 1; spin_unlock(&fc->lock); } return err;} /* * Unlock request. If it was interrupted during being locked, the * requester thread is currently waiting for it to be unlocked, so * wake it up. */static void unlock_request(struct fuse_conn *fc, struct fuse_req *req){ if (req) { spin_lock(&fc->lock); req->locked = 0; if (req->interrupted) wake_up(&req->waitq); spin_unlock(&fc->lock); }} struct fuse_copy_state { struct fuse_conn *fc; int write; struct fuse_req *req; const struct iovec *iov; unsigned long nr_segs; unsigned long seglen; unsigned long addr; struct page *pg; void *mapaddr; void *buf; unsigned len;}; static void fuse_copy_init(struct fuse_copy_state *cs, struct fuse_conn *fc, int write, struct fuse_req *req, const struct iovec *iov, unsigned long nr_segs){ memset(cs, 0, sizeof(*cs)); cs->fc = fc; cs->write = write; cs->req = req; cs->iov = iov; cs->nr_segs = nr_segs;} /* Unmap and put previous page of userspace buffer */static void fuse_copy_finish(struct fuse_copy_state *cs){ if (cs->mapaddr) { kunmap_atomic(cs->mapaddr, KM_USER0); if (cs->write) { flush_dcache_page(cs->pg); set_page_dirty_lock(cs->pg); } put_page(cs->pg); cs->mapaddr = NULL; }} /* * Get another pagefull of userspace buffer, and map it to kernel * address space, and lock request */static int fuse_copy_fill(struct fuse_copy_state *cs){ unsigned long offset; int err; unlock_request(cs->fc, cs->req); fuse_copy_finish(cs); if (!cs->seglen) { BUG_ON(!cs->nr_segs); cs->seglen = cs->iov[0].iov_len; cs->addr = (unsigned long) cs->iov[0].iov_base; cs->iov ++; cs->nr_segs --; } down_read(¤t->mm->mmap_sem); err = get_user_pages(current, current->mm, cs->addr, 1, cs->write, 0, &cs->pg, NULL); up_read(¤t->mm->mmap_sem); if (err < 0) return err; BUG_ON(err != 1); offset = cs->addr % PAGE_SIZE; cs->mapaddr = kmap_atomic(cs->pg, KM_USER0); cs->buf = cs->mapaddr + offset; cs->len = min(PAGE_SIZE - offset, cs->seglen); cs->seglen -= cs->len; cs->addr += cs->len; return lock_request(cs->fc, cs->req);} /* Do as much copy to/from userspace buffer as we can */static int fuse_copy_do(struct fuse_copy_state *cs, void **val, unsigned *size){ unsigned ncpy = min(*size, cs->len); if (val) { if (cs->write) memcpy(cs->buf, *val, ncpy); else memcpy(*val, cs->buf, ncpy); *val += ncpy; } *size -= ncpy; cs->len -= ncpy; cs->buf += ncpy; return ncpy;} /* * Copy a page in the request to/from the userspace buffer. Must be * done atomically */static int fuse_copy_page(struct fuse_copy_state *cs, struct page *page, unsigned offset, unsigned count, int zeroing){ if (page && zeroing && count < PAGE_SIZE) { void *mapaddr = kmap_atomic(page, KM_USER1); memset(mapaddr, 0, PAGE_SIZE); kunmap_atomic(mapaddr, KM_USER1); } while (count) { int err; if (!cs->len && (err = fuse_copy_fill(cs))) return err; if (page) { void *mapaddr = kmap_atomic(page, KM_USER1); void *buf = mapaddr + offset; offset += fuse_copy_do(cs, &buf, &count); kunmap_atomic(mapaddr, KM_USER1); } elseLines 1–500 of 964. Load more
/* FUSE: Filesystem in Userspace Copyright (C) 2001-2006 Miklos Szeredi <miklos@szeredi.hu> This program can be distributed under the terms of the GNU GPL. See the file COPYING. */ #include "fuse_i.h" #include <linux/init.h> #include <linux/module.h> #include <linux/poll.h> #include <linux/uio.h> #include <linux/miscdevice.h> #include <linux/pagemap.h> #include <linux/file.h> #include <linux/slab.h> MODULE_ALIAS_MISCDEV(FUSE_MINOR); static kmem_cache_t *fuse_req_cachep; static struct fuse_conn *fuse_get_conn(struct file *file) { /* * Lockless access is OK, because file->private data is set * once during mount and is valid until the file is released. */ return file->private_data; } static void fuse_request_init(struct fuse_req *req) { memset(req, 0, sizeof(*req)); INIT_LIST_HEAD(&req->list); init_waitqueue_head(&req->waitq); atomic_set(&req->count, 1); } struct fuse_req *fuse_request_alloc(void) { struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, SLAB_KERNEL); if (req) fuse_request_init(req); return req; } void fuse_request_free(struct fuse_req *req) { kmem_cache_free(fuse_req_cachep, req); } static void block_sigs(sigset_t *oldset) { sigset_t mask; siginitsetinv(&mask, sigmask(SIGKILL)); sigprocmask(SIG_BLOCK, &mask, oldset); } static void restore_sigs(sigset_t *oldset) { sigprocmask(SIG_SETMASK, oldset, NULL); } /* * Reset request, so that it can be reused * * The caller must be _very_ careful to make sure, that it is holding * the only reference to req */ void fuse_reset_request(struct fuse_req *req) { BUG_ON(atomic_read(&req->count) != 1); fuse_request_init(req); } static void __fuse_get_request(struct fuse_req *req) { atomic_inc(&req->count); } /* Must be called with > 1 refcount */ static void __fuse_put_request(struct fuse_req *req) { BUG_ON(atomic_read(&req->count) < 2); atomic_dec(&req->count); } struct fuse_req *fuse_get_req(struct fuse_conn *fc) { struct fuse_req *req; sigset_t oldset; int intr; int err; atomic_inc(&fc->num_waiting); block_sigs(&oldset); intr = wait_event_interruptible(fc->blocked_waitq, !fc->blocked); restore_sigs(&oldset); err = -EINTR; if (intr) goto out; req = fuse_request_alloc(); err = -ENOMEM; if (!req) goto out; req->in.h.uid = current->fsuid; req->in.h.gid = current->fsgid; req->in.h.pid = current->pid; req->waiting = 1; return req; out: atomic_dec(&fc->num_waiting); return ERR_PTR(err); } void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req) { if (atomic_dec_and_test(&req->count)) { if (req->waiting) atomic_dec(&fc->num_waiting); fuse_request_free(req); } } /* * Called with sbput_sem held for read (request_end) or write * (fuse_put_super). By the time fuse_put_super() is finished, all * inodes belonging to background requests must be released, so the * iputs have to be done within the locked region. */ void fuse_release_background(struct fuse_conn *fc, struct fuse_req *req) { iput(req->inode); iput(req->inode2); spin_lock(&fc->lock); list_del(&req->bg_entry); if (fc->num_background == FUSE_MAX_BACKGROUND) { fc->blocked = 0; wake_up_all(&fc->blocked_waitq); } fc->num_background--; spin_unlock(&fc->lock); } /* * This function is called when a request is finished. Either a reply * has arrived or it was interrupted (and not yet sent) or some error * occurred during communication with userspace, or the device file * was closed. In case of a background request the reference to the * stored objects are released. The requester thread is woken up (if * still waiting), the 'end' callback is called if given, else the * reference to the request is released * * Releasing extra reference for foreground requests must be done * within the same locked region as setting state to finished. This * is because fuse_reset_request() may be called after request is * finished and it must be the sole possessor. If request is * interrupted and put in the background, it will return with an error * and hence never be reset and reused. * * Called with fc->lock, unlocks it */ static void request_end(struct fuse_conn *fc, struct fuse_req *req) { list_del(&req->list); req->state = FUSE_REQ_FINISHED; if (!req->background) { spin_unlock(&fc->lock); wake_up(&req->waitq); fuse_put_request(fc, req); } else { void (*end) (struct fuse_conn *, struct fuse_req *) = req->end; req->end = NULL; spin_unlock(&fc->lock); down_read(&fc->sbput_sem); if (fc->mounted) fuse_release_background(fc, req); up_read(&fc->sbput_sem); /* fput must go outside sbput_sem, otherwise it can deadlock */ if (req->file) fput(req->file); if (end) end(fc, req); else fuse_put_request(fc, req); } } /* * Unfortunately request interruption not just solves the deadlock * problem, it causes problems too. These stem from the fact, that an * interrupted request is continued to be processed in userspace, * while all the locks and object references (inode and file) held * during the operation are released. * * To release the locks is exactly why there's a need to interrupt the * request, so there's not a lot that can be done about this, except * introduce additional locking in userspace. * * More important is to keep inode and file references until userspace * has replied, otherwise FORGET and RELEASE could be sent while the * inode/file is still used by the filesystem. * * For this reason the concept of "background" request is introduced. * An interrupted request is backgrounded if it has been already sent * to userspace. Backgrounding involves getting an extra reference to * inode(s) or file used in the request, and adding the request to * fc->background list. When a reply is received for a background * request, the object references are released, and the request is * removed from the list. If the filesystem is unmounted while there * are still background requests, the list is walked and references * are released as if a reply was received. * * There's one more use for a background request. The RELEASE message is * always sent as background, since it doesn't return an error or * data. */ static void background_request(struct fuse_conn *fc, struct fuse_req *req) { req->background = 1; list_add(&req->bg_entry, &fc->background); fc->num_background++; if (fc->num_background == FUSE_MAX_BACKGROUND) fc->blocked = 1; if (req->inode) req->inode = igrab(req->inode); if (req->inode2) req->inode2 = igrab(req->inode2); if (req->file) get_file(req->file); } /* Called with fc->lock held. Releases, and then reacquires it. */ static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req) { sigset_t oldset; spin_unlock(&fc->lock); block_sigs(&oldset); wait_event_interruptible(req->waitq, req->state == FUSE_REQ_FINISHED); restore_sigs(&oldset); spin_lock(&fc->lock); if (req->state == FUSE_REQ_FINISHED && !req->interrupted) return; if (!req->interrupted) { req->out.h.error = -EINTR; req->interrupted = 1; } if (req->locked) { /* This is uninterruptible sleep, because data is being copied to/from the buffers of req. During locked state, there mustn't be any filesystem operation (e.g. page fault), since that could lead to deadlock */ spin_unlock(&fc->lock); wait_event(req->waitq, !req->locked); spin_lock(&fc->lock); } if (req->state == FUSE_REQ_PENDING) { list_del(&req->list); __fuse_put_request(req); } else if (req->state == FUSE_REQ_SENT) background_request(fc, req); } static unsigned len_args(unsigned numargs, struct fuse_arg *args) { unsigned nbytes = 0; unsigned i; for (i = 0; i < numargs; i++) nbytes += args[i].size; return nbytes; } static void queue_request(struct fuse_conn *fc, struct fuse_req *req) { fc->reqctr++; /* zero is special */ if (fc->reqctr == 0) fc->reqctr = 1; req->in.h.unique = fc->reqctr; req->in.h.len = sizeof(struct fuse_in_header) + len_args(req->in.numargs, (struct fuse_arg *) req->in.args); list_add_tail(&req->list, &fc->pending); req->state = FUSE_REQ_PENDING; if (!req->waiting) { req->waiting = 1; atomic_inc(&fc->num_waiting); } wake_up(&fc->waitq); kill_fasync(&fc->fasync, SIGIO, POLL_IN); } /* * This can only be interrupted by a SIGKILL */ void request_send(struct fuse_conn *fc, struct fuse_req *req) { req->isreply = 1; spin_lock(&fc->lock); if (!fc->connected) req->out.h.error = -ENOTCONN; else if (fc->conn_error) req->out.h.error = -ECONNREFUSED; else { queue_request(fc, req); /* acquire extra reference, since request is still needed after request_end() */ __fuse_get_request(req); request_wait_answer(fc, req); } spin_unlock(&fc->lock); } static void request_send_nowait(struct fuse_conn *fc, struct fuse_req *req) { spin_lock(&fc->lock); background_request(fc, req); if (fc->connected) { queue_request(fc, req); spin_unlock(&fc->lock); } else { req->out.h.error = -ENOTCONN; request_end(fc, req); } } void request_send_noreply(struct fuse_conn *fc, struct fuse_req *req) { req->isreply = 0; request_send_nowait(fc, req); } void request_send_background(struct fuse_conn *fc, struct fuse_req *req) { req->isreply = 1; request_send_nowait(fc, req); } /* * Lock the request. Up to the next unlock_request() there mustn't be * anything that could cause a page-fault. If the request was already * interrupted bail out. */ static int lock_request(struct fuse_conn *fc, struct fuse_req *req) { int err = 0; if (req) { spin_lock(&fc->lock); if (req->interrupted) err = -ENOENT; else req->locked = 1; spin_unlock(&fc->lock); } return err; } /* * Unlock request. If it was interrupted during being locked, the * requester thread is currently waiting for it to be unlocked, so * wake it up. */ static void unlock_request(struct fuse_conn *fc, struct fuse_req *req) { if (req) { spin_lock(&fc->lock); req->locked = 0; if (req->interrupted) wake_up(&req->waitq); spin_unlock(&fc->lock); } } struct fuse_copy_state { struct fuse_conn *fc; int write; struct fuse_req *req; const struct iovec *iov; unsigned long nr_segs; unsigned long seglen; unsigned long addr; struct page *pg; void *mapaddr; void *buf; unsigned len; }; static void fuse_copy_init(struct fuse_copy_state *cs, struct fuse_conn *fc, int write, struct fuse_req *req, const struct iovec *iov, unsigned long nr_segs) { memset(cs, 0, sizeof(*cs)); cs->fc = fc; cs->write = write; cs->req = req; cs->iov = iov; cs->nr_segs = nr_segs; } /* Unmap and put previous page of userspace buffer */ static void fuse_copy_finish(struct fuse_copy_state *cs) { if (cs->mapaddr) { kunmap_atomic(cs->mapaddr, KM_USER0); if (cs->write) { flush_dcache_page(cs->pg); set_page_dirty_lock(cs->pg); } put_page(cs->pg); cs->mapaddr = NULL; } } /* * Get another pagefull of userspace buffer, and map it to kernel * address space, and lock request */ static int fuse_copy_fill(struct fuse_copy_state *cs) { unsigned long offset; int err; unlock_request(cs->fc, cs->req); fuse_copy_finish(cs); if (!cs->seglen) { BUG_ON(!cs->nr_segs); cs->seglen = cs->iov[0].iov_len; cs->addr = (unsigned long) cs->iov[0].iov_base; cs->iov ++; cs->nr_segs --; } down_read(¤t->mm->mmap_sem); err = get_user_pages(current, current->mm, cs->addr, 1, cs->write, 0, &cs->pg, NULL); up_read(¤t->mm->mmap_sem); if (err < 0) return err; BUG_ON(err != 1); offset = cs->addr % PAGE_SIZE; cs->mapaddr = kmap_atomic(cs->pg, KM_USER0); cs->buf = cs->mapaddr + offset; cs->len = min(PAGE_SIZE - offset, cs->seglen); cs->seglen -= cs->len; cs->addr += cs->len; return lock_request(cs->fc, cs->req); } /* Do as much copy to/from userspace buffer as we can */ static int fuse_copy_do(struct fuse_copy_state *cs, void **val, unsigned *size) { unsigned ncpy = min(*size, cs->len); if (val) { if (cs->write) memcpy(cs->buf, *val, ncpy); else memcpy(*val, cs->buf, ncpy); *val += ncpy; } *size -= ncpy; cs->len -= ncpy; cs->buf += ncpy; return ncpy; } /* * Copy a page in the request to/from the userspace buffer. Must be * done atomically */ static int fuse_copy_page(struct fuse_copy_state *cs, struct page *page, unsigned offset, unsigned count, int zeroing) { if (page && zeroing && count < PAGE_SIZE) { void *mapaddr = kmap_atomic(page, KM_USER1); memset(mapaddr, 0, PAGE_SIZE); kunmap_atomic(mapaddr, KM_USER1); } while (count) { int err; if (!cs->len && (err = fuse_copy_fill(cs))) return err; if (page) { void *mapaddr = kmap_atomic(page, KM_USER1); void *buf = mapaddr + offset; offset += fuse_copy_do(cs, &buf, &count); kunmap_atomic(mapaddr, KM_USER1); } else