[Devel] [PATCH RHEL7 COMMIT] fuse/kio_pcs: full fallocate() support
Konstantin Khorenko
khorenko at virtuozzo.com
Fri Apr 27 12:09:00 MSK 2018
The commit is pushed to "branch-rh7-3.10.0-693.21.1.vz7.47.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-693.21.1.vz7.46.7
------>
commit a4fdfacf2c5de6fb2b931f4a274ee878eed40660
Author: Alexey Kuznetsov <kuznet at virtuozzo.com>
Date: Fri Apr 27 12:09:00 2018 +0300
fuse/kio_pcs: full fallocate() support
Signed-off-by: Alexey Kuznetsov <kuznet at virtuozzo.com>
Signed-off-by: Dmitry Monakhov <dmonakhov at openvz.org>
---
fs/fuse/kio/pcs/fuse_io.c | 46 ++++++++++++++++++++++++++++
fs/fuse/kio/pcs/pcs_cluster.c | 7 +++--
fs/fuse/kio/pcs/pcs_cluster.h | 1 +
fs/fuse/kio/pcs/pcs_fuse_kdirect.c | 62 +++++++++++++++++++++++++++++++++++---
4 files changed, 108 insertions(+), 8 deletions(-)
diff --git a/fs/fuse/kio/pcs/fuse_io.c b/fs/fuse/kio/pcs/fuse_io.c
index 97802e143cb1..47950d26757f 100644
--- a/fs/fuse/kio/pcs/fuse_io.c
+++ b/fs/fuse/kio/pcs/fuse_io.c
@@ -73,6 +73,17 @@ static void on_write_done(struct pcs_fuse_req *r, off_t pos, size_t size)
request_end(pfc->fc, &r->req);
}
+static void on_fallocate_done(struct pcs_fuse_req *r, off_t pos, size_t size)
+{
+ struct pcs_fuse_cluster *pfc = cl_from_req(r);
+
+ DTRACE("do fuse_request_end req:%p op:%d err:%d\n", &r->req, r->req.in.h.opcode, r->req.out.h.error);
+ fuse_stat_account(pfc->fc, KFUSE_OP_FALLOCATE, ktime_sub(ktime_get(), r->exec.ireq.ts));
+ inode_dio_end(r->req.io_inode);
+
+ request_end(pfc->fc, &r->req);
+}
+
static void req_get_iter(void *data, unsigned int offset, struct iov_iter *it)
{
struct pcs_fuse_req *r = data;
@@ -134,6 +145,11 @@ static void prepare_io_(struct pcs_fuse_req *r, unsigned short type, off_t offse
BUG_ON(r->req.in.argbvec && r->req.in.argpages);
set_io_buff(r, offset, size, r->req.in.argbvec, 0);
break;
+ case PCS_REQ_T_WRITE_ZERO:
+ case PCS_REQ_T_WRITE_HOLE:
+ r->exec.io.req.pos = offset;
+ r->exec.io.req.size = size;
+ break;
}
r->exec.io.req.type = type;
@@ -176,6 +192,10 @@ static void ioreq_complete(pcs_api_iorequest_t *ioreq)
case PCS_REQ_T_SYNC:
on_sync_done(r);
break;
+ case PCS_REQ_T_WRITE_HOLE:
+ case PCS_REQ_T_WRITE_ZERO:
+ on_fallocate_done(r, ioreq->pos, ioreq->size);
+ break;
default:
BUG();
}
@@ -186,3 +206,29 @@ void pcs_fuse_prep_io(struct pcs_fuse_req *r, unsigned short type, off_t offset,
{
prepare_io_(r, type, offset, size, ioreq_complete);
}
+
+static void falloc_req_complete(struct pcs_int_request *ireq)
+{
+ struct pcs_fuse_req * r = ireq->completion_data.priv;
+ struct pcs_fuse_cluster *pfc = cl_from_req(r);
+
+ BUG_ON(ireq->type != PCS_IREQ_NOOP);
+
+ DTRACE("do fuse_request_end req:%p op:%d err:%d\n", &r->req, r->req.in.h.opcode, r->req.out.h.error);
+ fuse_stat_account(pfc->fc, KFUSE_OP_FALLOCATE, ktime_sub(ktime_get(), ireq->ts));
+ inode_dio_end(r->req.io_inode);
+
+ request_end(pfc->fc, &r->req);
+}
+
+void pcs_fuse_prep_fallocate(struct pcs_fuse_req *r)
+{
+ struct pcs_int_request *ireq = &r->exec.ireq;
+
+ ireq->type = PCS_IREQ_NOOP;
+ ireq->ts = ktime_get();
+ ireq->complete_cb = falloc_req_complete;
+ ireq->completion_data.parent = 0;
+ ireq->completion_data.ctx = r;
+ ireq->completion_data.priv = r;
+}
diff --git a/fs/fuse/kio/pcs/pcs_cluster.c b/fs/fuse/kio/pcs/pcs_cluster.c
index 8514e5ed06ce..2d988484ec94 100644
--- a/fs/fuse/kio/pcs/pcs_cluster.c
+++ b/fs/fuse/kio/pcs/pcs_cluster.c
@@ -169,18 +169,19 @@ static noinline void __pcs_cc_process_ireq_rw(struct pcs_int_request *ireq)
static void pcs_cc_process_ireq_ioreq(struct pcs_int_request *ireq)
{
-
if (ireq->apireq.req->type == PCS_REQ_T_SYNC) {
map_inject_flush_req(ireq);
return;
}
if (ireq->apireq.req->type != PCS_REQ_T_READ &&
- ireq->apireq.req->type != PCS_REQ_T_WRITE) {
+ ireq->apireq.req->type != PCS_REQ_T_WRITE &&
+ ireq->apireq.req->type != PCS_REQ_T_WRITE_HOLE &&
+ ireq->apireq.req->type != PCS_REQ_T_WRITE_ZERO) {
pcs_set_local_error(&ireq->error, PCS_ERR_PROTOCOL);
ireq_complete(ireq);
+ return;
}
return __pcs_cc_process_ireq_rw(ireq);
-
}
static void ireq_process_(struct pcs_int_request *ireq)
diff --git a/fs/fuse/kio/pcs/pcs_cluster.h b/fs/fuse/kio/pcs/pcs_cluster.h
index 8b58d3cd946b..f1c20797d951 100644
--- a/fs/fuse/kio/pcs/pcs_cluster.h
+++ b/fs/fuse/kio/pcs/pcs_cluster.h
@@ -102,6 +102,7 @@ int pcs_cc_init(struct pcs_cluster_core *cc, struct workqueue_struct *wq,
void pcs_cc_fini(struct pcs_cluster_core *cc);
void pcs_fuse_prep_io(struct pcs_fuse_req *r, unsigned short type, off_t offset, size_t size);
+void pcs_fuse_prep_fallocate(struct pcs_fuse_req *r);
int fuse_pcs_csconn_send(struct fuse_conn *fc, struct pcs_rpc *ep, int flags);
diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
index bae89deffde2..70a7b38e3692 100644
--- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
+++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
@@ -58,9 +58,6 @@ static void process_pcs_init_reply(struct fuse_conn *fc, struct fuse_req *req)
fc->conn_error = 1;
goto out;
}
- /* TODO: Not yet implemented PSBM-80365 */
- fc->no_fiemap = 1;
- fc->no_fallocate = 1;
fc->kio.ctx = pfc;
printk("FUSE: kio_pcs: cl: " CLUSTER_ID_FMT ", clientid: " NODE_FMT "\n",
@@ -694,7 +691,7 @@ static void wait_grow(struct pcs_fuse_req *r, struct pcs_dentry_info *di, unsign
{
assert_spin_locked(&di->lock);
BUG_ON(r->exec.size.waiting);
- BUG_ON(r->req.in.h.opcode != FUSE_WRITE);
+ BUG_ON(r->req.in.h.opcode != FUSE_WRITE && r->req.in.h.opcode != FUSE_FALLOCATE);
TRACE("insert ino:%ld->required:%lld r(%p)->required:%lld\n", r->req.io_inode->i_ino,
di->size.required, r, required);
@@ -705,6 +702,7 @@ static void wait_grow(struct pcs_fuse_req *r, struct pcs_dentry_info *di, unsign
if (!di->size.required)
queue_work(pcs_wq, &di->size.work);
}
+
static void wait_shrink(struct pcs_fuse_req *r, struct pcs_dentry_info *di)
{
assert_spin_locked(&di->lock);
@@ -751,7 +749,7 @@ static int pcs_fuse_prep_rw(struct pcs_fuse_req *r)
size = di->fileinfo.attr.size - in->offset;
}
pcs_fuse_prep_io(r, PCS_REQ_T_READ, in->offset, size);
- } else {
+ } else if (r->req.in.h.opcode == FUSE_WRITE) {
struct fuse_write_in *in = &r->req.misc.write.in;
if (in->offset + in->size > di->fileinfo.attr.size) {
@@ -759,7 +757,26 @@ static int pcs_fuse_prep_rw(struct pcs_fuse_req *r)
ret = 1;
}
pcs_fuse_prep_io(r, PCS_REQ_T_WRITE, in->offset, in->size);
+ } else {
+ struct fuse_fallocate_in const *in = r->req.in.args[0].value;
+
+ if (in->offset + in->length > di->fileinfo.attr.size) {
+ wait_grow(r, di, in->offset + in->length);
+ ret = 1;
+ }
+ if (in->mode & FALLOC_FL_PUNCH_HOLE)
+ pcs_fuse_prep_io(r, PCS_REQ_T_WRITE_HOLE, in->offset, in->length);
+ else if (in->mode & FALLOC_FL_ZERO_RANGE)
+ pcs_fuse_prep_io(r, PCS_REQ_T_WRITE_ZERO, in->offset, in->length);
+ else {
+ if (ret) {
+ pcs_fuse_prep_fallocate(r);
+ } else {
+ spin_unlock(&di->lock);
+ return -1;
+ }
+ }
}
inode_dio_begin(r->req.io_inode);
spin_unlock(&di->lock);
@@ -796,15 +813,49 @@ static void pcs_fuse_submit(struct pcs_fuse_cluster *pfc, struct fuse_req *req,
return;
break;
}
+ case FUSE_FALLOCATE: {
+ int ret;
+ struct fuse_fallocate_in *inarg = (void*) req->in.args[0].value;
+
+ if (pfc->fc->no_fallocate) {
+ r->req.out.h.error = -EOPNOTSUPP;
+ goto error;
+ }
+
+ if (inarg->offset >= di->fileinfo.attr.size)
+ inarg->mode &= ~FALLOC_FL_ZERO_RANGE;
+
+ if (inarg->mode & FALLOC_FL_KEEP_SIZE) {
+ if (inarg->offset + inarg->length > di->fileinfo.attr.size)
+ inarg->length = di->fileinfo.attr.size - inarg->offset;
+ }
+
+ if (inarg->mode & (FALLOC_FL_ZERO_RANGE|FALLOC_FL_PUNCH_HOLE)) {
+ if ((inarg->offset & (PAGE_SIZE - 1)) || (inarg->length & (PAGE_SIZE - 1))) {
+ r->req.out.h.error = -EINVAL;
+ goto error;
+ }
+ }
+
+ ret = pcs_fuse_prep_rw(r);
+ if (!ret)
+ goto submit;
+ if (ret > 0)
+ /* Pended, nothing to do. */
+ return;
+ break;
+ }
case FUSE_FSYNC:
pcs_fuse_prep_io(r, PCS_REQ_T_SYNC, 0, 0);
goto submit;
}
r->req.out.h.error = 0;
+error:
DTRACE("do fuse_request_end req:%p op:%d err:%d\n", &r->req, r->req.in.h.opcode, r->req.out.h.error);
request_end(pfc->fc, &r->req);
return;
+
submit:
if (async)
pcs_cc_submit(ireq->cc, ireq);
@@ -934,6 +985,7 @@ static int kpcs_req_send(struct fuse_conn* fc, struct fuse_req *req, bool bg, bo
case FUSE_READ:
case FUSE_WRITE:
case FUSE_FSYNC:
+ case FUSE_FALLOCATE:
fi = get_fuse_inode(req->io_inode);
if (!fi->private)
return 1;
More information about the Devel
mailing list