提交 57f16587 编写于 作者: S Stefan Hajnoczi 提交者: Caspar Zhang

fuse: add fuse_iqueue_ops callbacks

task #28910367
commit ae3aad77f46fbba56eff7141b2fc49870b60827e upstream

The /dev/fuse device uses fiq->waitq and fasync to signal that requests
are available.  These mechanisms do not apply to virtio-fs.  This patch
introduces callbacks so alternative behavior can be used.

Note that queue_interrupt() changes along these lines:

  spin_lock(&fiq->waitq.lock);
  wake_up_locked(&fiq->waitq);
+ kill_fasync(&fiq->fasync, SIGIO, POLL_IN);
  spin_unlock(&fiq->waitq.lock);
- kill_fasync(&fiq->fasync, SIGIO, POLL_IN);

Since queue_request() and queue_forget() also call kill_fasync() inside
the spinlock this should be safe.
Signed-off-by: NStefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: NLiu Bo <bo.liu@linux.alibaba.com>
Reviewed-by: NJoseph Qi <joseph.qi@linux.alibaba.com>
上级 6769b1fd
......@@ -503,7 +503,7 @@ static int cuse_channel_open(struct inode *inode, struct file *file)
* Limit the cuse channel to requests that can
* be represented in file->f_cred->user_ns.
*/
fuse_conn_init(&cc->fc, file->f_cred->user_ns);
fuse_conn_init(&cc->fc, file->f_cred->user_ns, &fuse_dev_fiq_ops, NULL);
fud = fuse_dev_alloc(&cc->fc);
if (!fud) {
......
......@@ -327,13 +327,33 @@ static u64 fuse_get_unique(struct fuse_iqueue *fiq)
return ++fiq->reqctr;
}
static void queue_request(struct fuse_iqueue *fiq, struct fuse_req *req)
/**
* A new request is available, wake fiq->waitq
*/
static void fuse_dev_wake_and_unlock(struct fuse_iqueue *fiq)
__releases(fiq->lock)
{
req->in.h.len = sizeof(struct fuse_in_header) +
fuse_len_args(req->in.numargs, (struct fuse_arg *)req->in.args);
list_add_tail(&req->list, &fiq->pending);
wake_up(&fiq->waitq);
kill_fasync(&fiq->fasync, SIGIO, POLL_IN);
spin_unlock(&fiq->lock);
}
const struct fuse_iqueue_ops fuse_dev_fiq_ops = {
.wake_forget_and_unlock = fuse_dev_wake_and_unlock,
.wake_interrupt_and_unlock = fuse_dev_wake_and_unlock,
.wake_pending_and_unlock = fuse_dev_wake_and_unlock,
};
EXPORT_SYMBOL_GPL(fuse_dev_fiq_ops);
static void queue_request_and_unlock(struct fuse_iqueue *fiq,
struct fuse_req *req)
__releases(fiq->lock)
{
req->in.h.len = sizeof(struct fuse_in_header) +
fuse_len_args(req->in.numargs,
(struct fuse_arg *) req->in.args);
list_add_tail(&req->list, &fiq->pending);
fiq->ops->wake_pending_and_unlock(fiq);
}
void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget,
......@@ -348,12 +368,11 @@ void fuse_queue_forget(struct fuse_conn *fc, struct fuse_forget_link *forget,
if (fiq->connected) {
fiq->forget_list_tail->next = forget;
fiq->forget_list_tail = forget;
wake_up(&fiq->waitq);
kill_fasync(&fiq->fasync, SIGIO, POLL_IN);
fiq->ops->wake_forget_and_unlock(fiq);
} else {
kfree(forget);
spin_unlock(&fiq->lock);
}
spin_unlock(&fiq->lock);
}
static void flush_bg_queue(struct fuse_conn *fc)
......@@ -368,8 +387,7 @@ static void flush_bg_queue(struct fuse_conn *fc)
fc->active_background++;
spin_lock(&fiq->lock);
req->in.h.unique = fuse_get_unique(fiq);
queue_request(fiq, req);
spin_unlock(&fiq->lock);
queue_request_and_unlock(fiq, req);
}
}
......@@ -436,10 +454,10 @@ static void queue_interrupt(struct fuse_iqueue *fiq, struct fuse_req *req)
}
if (list_empty(&req->intr_entry)) {
list_add_tail(&req->intr_entry, &fiq->interrupts);
wake_up(&fiq->waitq);
fiq->ops->wake_interrupt_and_unlock(fiq);
} else {
spin_unlock(&fiq->lock);
}
spin_unlock(&fiq->lock);
kill_fasync(&fiq->fasync, SIGIO, POLL_IN);
}
static void request_wait_answer(struct fuse_conn *fc, struct fuse_req *req)
......@@ -498,13 +516,12 @@ static void __fuse_request_send(struct fuse_conn *fc, struct fuse_req *req)
req->out.h.error = -ENOTCONN;
} else {
req->in.h.unique = fuse_get_unique(fiq);
queue_request(fiq, req);
/*
* acquire extra reference, since request is still
* needed after fuse_request_end()
*/
__fuse_get_request(req);
spin_unlock(&fiq->lock);
queue_request_and_unlock(fiq, req);
request_wait_answer(fc, req);
/* Pairs with smp_wmb() in fuse_request_end() */
......@@ -639,10 +656,11 @@ static int fuse_request_send_notify_reply(struct fuse_conn *fc,
req->in.h.unique = unique;
spin_lock(&fiq->lock);
if (fiq->connected) {
queue_request(fiq, req);
queue_request_and_unlock(fiq, req);
err = 0;
} else {
spin_unlock(&fiq->lock);
}
spin_unlock(&fiq->lock);
return err;
}
......
......@@ -400,6 +400,39 @@ struct fuse_req {
struct file *stolen_file;
};
struct fuse_iqueue;
/**
* Input queue callbacks
*
* Input queue signalling is device-specific. For example, the /dev/fuse file
* uses fiq->waitq and fasync to wake processes that are waiting on queue
* readiness. These callbacks allow other device types to respond to input
* queue activity.
*/
struct fuse_iqueue_ops {
/**
* Signal that a forget has been queued
*/
void (*wake_forget_and_unlock)(struct fuse_iqueue *fiq)
__releases(fiq->lock);
/**
* Signal that an INTERRUPT request has been queued
*/
void (*wake_interrupt_and_unlock)(struct fuse_iqueue *fiq)
__releases(fiq->lock);
/**
* Signal that a request has been queued
*/
void (*wake_pending_and_unlock)(struct fuse_iqueue *fiq)
__releases(fiq->lock);
};
/** /dev/fuse input queue operations */
extern const struct fuse_iqueue_ops fuse_dev_fiq_ops;
struct fuse_iqueue {
/** Connection established */
unsigned connected;
......@@ -428,6 +461,12 @@ struct fuse_iqueue {
/** O_ASYNC requests */
struct fasync_struct *fasync;
/** Device-specific callbacks */
const struct fuse_iqueue_ops *ops;
/** Device-specific state */
void *priv;
};
struct fuse_pqueue {
......@@ -908,7 +947,8 @@ struct fuse_conn *fuse_conn_get(struct fuse_conn *fc);
/**
* Initialize fuse_conn
*/
void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns);
void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns,
const struct fuse_iqueue_ops *fiq_ops, void *fiq_priv);
/**
* Release reference to fuse_conn
......@@ -928,10 +968,14 @@ int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev,
* Fill in superblock and initialize fuse connection
* @sb: partially-initialized superblock to fill in
* @mount_data: mount parameters
* @fiq_ops: fuse input queue operations
* @fiq_priv: device-specific state for fuse_iqueue
* @fudptr: fuse_dev pointer to fill in, should contain NULL on entry
*/
int fuse_fill_super_common(struct super_block *sb,
struct fuse_mount_data *mount_data,
const struct fuse_iqueue_ops *fiq_ops,
void *fiq_priv,
void **fudptr);
void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req);
......
......@@ -568,7 +568,9 @@ static int fuse_show_options(struct seq_file *m, struct dentry *root)
return 0;
}
static void fuse_iqueue_init(struct fuse_iqueue *fiq)
static void fuse_iqueue_init(struct fuse_iqueue *fiq,
const struct fuse_iqueue_ops *ops,
void *priv)
{
memset(fiq, 0, sizeof(struct fuse_iqueue));
spin_lock_init(&fiq->lock);
......@@ -577,6 +579,8 @@ static void fuse_iqueue_init(struct fuse_iqueue *fiq)
INIT_LIST_HEAD(&fiq->interrupts);
fiq->forget_list_tail = &fiq->forget_list_head;
fiq->connected = 1;
fiq->ops = ops;
fiq->priv = priv;
}
static void fuse_pqueue_init(struct fuse_pqueue *fpq)
......@@ -588,7 +592,8 @@ static void fuse_pqueue_init(struct fuse_pqueue *fpq)
fpq->connected = 1;
}
void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns)
void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns,
const struct fuse_iqueue_ops *fiq_ops, void *fiq_priv)
{
memset(fc, 0, sizeof(*fc));
spin_lock_init(&fc->lock);
......@@ -597,7 +602,7 @@ void fuse_conn_init(struct fuse_conn *fc, struct user_namespace *user_ns)
atomic_set(&fc->dev_count, 1);
init_waitqueue_head(&fc->blocked_waitq);
init_waitqueue_head(&fc->reserved_req_waitq);
fuse_iqueue_init(&fc->iq);
fuse_iqueue_init(&fc->iq, fiq_ops, fiq_priv);
INIT_LIST_HEAD(&fc->bg_queue);
INIT_LIST_HEAD(&fc->entry);
INIT_LIST_HEAD(&fc->devices);
......@@ -1042,6 +1047,8 @@ EXPORT_SYMBOL_GPL(fuse_dev_free);
int fuse_fill_super_common(struct super_block *sb,
struct fuse_mount_data *mount_data,
const struct fuse_iqueue_ops *fiq_ops,
void *fiq_priv,
void **fudptr)
{
struct fuse_dev *fud;
......@@ -1089,7 +1096,7 @@ int fuse_fill_super_common(struct super_block *sb,
if (!fc)
goto err;
fuse_conn_init(fc, sb->s_user_ns);
fuse_conn_init(fc, sb->s_user_ns, fiq_ops, fiq_priv);
fc->release = fuse_free_conn;
fud = fuse_dev_alloc(fc);
......@@ -1191,7 +1198,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent)
goto err_fput;
__set_bit(FR_BACKGROUND, &init_req->flags);
err = fuse_fill_super_common(sb, &d, &file->private_data);
err = fuse_fill_super_common(sb, &d, &fuse_dev_fiq_ops, NULL,
&file->private_data);
if (err < 0)
goto err_free_init_req;
/*
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册