Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/mszeredi/fuse

Pull fuse updates from Miklos Szeredi:
 "This contains two patchsets from Maxim Patlasov.

  The first reworks the request throttling so that only async requests
  are throttled.  Wakeup of waiting async requests is also optimized.

  The second series adds support for async processing of direct IO which
  optimizes direct IO and enables the use of the AIO userspace
  interface."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/fuse:
  fuse: add flag to turn on async direct IO
  fuse: truncate file if async dio failed
  fuse: optimize short direct reads
  fuse: enable asynchronous processing direct IO
  fuse: make fuse_direct_io() aware about AIO
  fuse: add support of async IO
  fuse: move fuse_release_user_pages() up
  fuse: optimize wake_up
  fuse: implement exclusive wakeup for blocked_waitq
  fuse: skip blocking on allocations of synchronous requests
  fuse: add flag fc->initialized
  fuse: make request allocations for background processing explicit
  • Loading branch information
Linus Torvalds committed May 7, 2013
2 parents c818c77 + 60b9df7 commit a26ea93
Show file tree
Hide file tree
Showing 7 changed files with 362 additions and 72 deletions.
10 changes: 6 additions & 4 deletions fs/fuse/cuse.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,21 +92,23 @@ static ssize_t cuse_read(struct file *file, char __user *buf, size_t count,
{
loff_t pos = 0;
struct iovec iov = { .iov_base = buf, .iov_len = count };
struct fuse_io_priv io = { .async = 0, .file = file };

return fuse_direct_io(file, &iov, 1, count, &pos, 0);
return fuse_direct_io(&io, &iov, 1, count, &pos, 0);
}

static ssize_t cuse_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
loff_t pos = 0;
struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count };
struct fuse_io_priv io = { .async = 0, .file = file };

/*
* No locking or generic_write_checks(), the server is
* responsible for locking and sanity checks.
*/
return fuse_direct_io(file, &iov, 1, count, &pos, 1);
return fuse_direct_io(&io, &iov, 1, count, &pos, 1);
}

static int cuse_open(struct inode *inode, struct file *file)
Expand Down Expand Up @@ -422,7 +424,7 @@ static int cuse_send_init(struct cuse_conn *cc)

BUILD_BUG_ON(CUSE_INIT_INFO_MAX > PAGE_SIZE);

req = fuse_get_req(fc, 1);
req = fuse_get_req_for_background(fc, 1);
if (IS_ERR(req)) {
rc = PTR_ERR(req);
goto err;
Expand Down Expand Up @@ -504,7 +506,7 @@ static int cuse_channel_open(struct inode *inode, struct file *file)
cc->fc.release = cuse_fc_release;

cc->fc.connected = 1;
cc->fc.blocked = 0;
cc->fc.initialized = 1;
rc = cuse_send_init(cc);
if (rc) {
fuse_conn_put(&cc->fc);
Expand Down
80 changes: 63 additions & 17 deletions fs/fuse/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ static void restore_sigs(sigset_t *oldset)
sigprocmask(SIG_SETMASK, oldset, NULL);
}

static void __fuse_get_request(struct fuse_req *req)
void __fuse_get_request(struct fuse_req *req)
{
atomic_inc(&req->count);
}
Expand All @@ -130,40 +130,66 @@ static void fuse_req_init_context(struct fuse_req *req)
req->in.h.pid = current->pid;
}

struct fuse_req *fuse_get_req(struct fuse_conn *fc, unsigned npages)
static bool fuse_block_alloc(struct fuse_conn *fc, bool for_background)
{
return !fc->initialized || (for_background && fc->blocked);
}

static struct fuse_req *__fuse_get_req(struct fuse_conn *fc, unsigned npages,
bool for_background)
{
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;

if (fuse_block_alloc(fc, for_background)) {
sigset_t oldset;
int intr;

block_sigs(&oldset);
intr = wait_event_interruptible_exclusive(fc->blocked_waitq,
!fuse_block_alloc(fc, for_background));
restore_sigs(&oldset);
err = -EINTR;
if (intr)
goto out;
}

err = -ENOTCONN;
if (!fc->connected)
goto out;

req = fuse_request_alloc(npages);
err = -ENOMEM;
if (!req)
if (!req) {
if (for_background)
wake_up(&fc->blocked_waitq);
goto out;
}

fuse_req_init_context(req);
req->waiting = 1;
req->background = for_background;
return req;

out:
atomic_dec(&fc->num_waiting);
return ERR_PTR(err);
}

struct fuse_req *fuse_get_req(struct fuse_conn *fc, unsigned npages)
{
return __fuse_get_req(fc, npages, false);
}
EXPORT_SYMBOL_GPL(fuse_get_req);

struct fuse_req *fuse_get_req_for_background(struct fuse_conn *fc,
unsigned npages)
{
return __fuse_get_req(fc, npages, true);
}
EXPORT_SYMBOL_GPL(fuse_get_req_for_background);

/*
* Return request in fuse_file->reserved_req. However that may
* currently be in use. If that is the case, wait for it to become
Expand Down Expand Up @@ -225,19 +251,31 @@ struct fuse_req *fuse_get_req_nofail_nopages(struct fuse_conn *fc,
struct fuse_req *req;

atomic_inc(&fc->num_waiting);
wait_event(fc->blocked_waitq, !fc->blocked);
wait_event(fc->blocked_waitq, fc->initialized);
req = fuse_request_alloc(0);
if (!req)
req = get_reserved_req(fc, file);

fuse_req_init_context(req);
req->waiting = 1;
req->background = 0;
return req;
}

void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
{
if (atomic_dec_and_test(&req->count)) {
if (unlikely(req->background)) {
/*
* We get here in the unlikely case that a background
* request was allocated but not sent
*/
spin_lock(&fc->lock);
if (!fc->blocked)
wake_up(&fc->blocked_waitq);
spin_unlock(&fc->lock);
}

if (req->waiting)
atomic_dec(&fc->num_waiting);

Expand Down Expand Up @@ -335,10 +373,15 @@ __releases(fc->lock)
list_del(&req->intr_entry);
req->state = FUSE_REQ_FINISHED;
if (req->background) {
if (fc->num_background == fc->max_background) {
req->background = 0;

if (fc->num_background == fc->max_background)
fc->blocked = 0;
wake_up_all(&fc->blocked_waitq);
}

/* Wake up next waiter, if any */
if (!fc->blocked && waitqueue_active(&fc->blocked_waitq))
wake_up(&fc->blocked_waitq);

if (fc->num_background == fc->congestion_threshold &&
fc->connected && fc->bdi_initialized) {
clear_bdi_congested(&fc->bdi, BLK_RW_SYNC);
Expand Down Expand Up @@ -442,6 +485,7 @@ __acquires(fc->lock)

static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
{
BUG_ON(req->background);
spin_lock(&fc->lock);
if (!fc->connected)
req->out.h.error = -ENOTCONN;
Expand Down Expand Up @@ -469,7 +513,7 @@ EXPORT_SYMBOL_GPL(fuse_request_send);
static void fuse_request_send_nowait_locked(struct fuse_conn *fc,
struct fuse_req *req)
{
req->background = 1;
BUG_ON(!req->background);
fc->num_background++;
if (fc->num_background == fc->max_background)
fc->blocked = 1;
Expand Down Expand Up @@ -2071,6 +2115,7 @@ void fuse_abort_conn(struct fuse_conn *fc)
if (fc->connected) {
fc->connected = 0;
fc->blocked = 0;
fc->initialized = 1;
end_io_requests(fc);
end_queued_requests(fc);
end_polls(fc);
Expand All @@ -2089,6 +2134,7 @@ int fuse_dev_release(struct inode *inode, struct file *file)
spin_lock(&fc->lock);
fc->connected = 0;
fc->blocked = 0;
fc->initialized = 1;
end_queued_requests(fc);
end_polls(fc);
wake_up_all(&fc->blocked_waitq);
Expand Down
17 changes: 9 additions & 8 deletions fs/fuse/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -1562,10 +1562,9 @@ void fuse_release_nowrite(struct inode *inode)
* vmtruncate() doesn't allow for this case, so do the rlimit checking
* and the actual truncation by hand.
*/
static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
struct file *file)
int fuse_do_setattr(struct inode *inode, struct iattr *attr,
struct file *file)
{
struct inode *inode = entry->d_inode;
struct fuse_conn *fc = get_fuse_conn(inode);
struct fuse_req *req;
struct fuse_setattr_in inarg;
Expand All @@ -1574,9 +1573,6 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,
loff_t oldsize;
int err;

if (!fuse_allow_current_process(fc))
return -EACCES;

if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS))
attr->ia_valid |= ATTR_FORCE;

Expand Down Expand Up @@ -1671,10 +1667,15 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr,

static int fuse_setattr(struct dentry *entry, struct iattr *attr)
{
struct inode *inode = entry->d_inode;

if (!fuse_allow_current_process(get_fuse_conn(inode)))
return -EACCES;

if (attr->ia_valid & ATTR_FILE)
return fuse_do_setattr(entry, attr, attr->ia_file);
return fuse_do_setattr(inode, attr, attr->ia_file);
else
return fuse_do_setattr(entry, attr, NULL);
return fuse_do_setattr(inode, attr, NULL);
}

static int fuse_getattr(struct vfsmount *mnt, struct dentry *entry,
Expand Down
Loading

0 comments on commit a26ea93

Please sign in to comment.