[RHEL7,COMMIT] fuse/kio_pcs: full fallocate() support

Submitted by Konstantin Khorenko on April 27, 2018, 9:09 a.m.

Details

Message ID 201804270909.w3R9904u031413@finist_ce7.work
State New
Series "fuse/kio_pcs: full fallocate() support"
Headers show

Commit Message

Konstantin Khorenko April 27, 2018, 9:09 a.m.
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@virtuozzo.com>
Date:   Fri Apr 27 12:09:00 2018 +0300

    fuse/kio_pcs: full fallocate() support
    
    Signed-off-by: Alexey Kuznetsov <kuznet@virtuozzo.com>
    Signed-off-by: Dmitry Monakhov <dmonakhov@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(-)

Patch hide | download patch | download mbox

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;