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 9227091012d80d24aecbbae42c13c3510e73d4c4
Author: Alexey Kuznetsov <[email protected]>
Date:   Fri Apr 27 12:09:01 2018 +0300

    fuse/kio_pcs: FIEMAP support
    
    Signed-off-by: Alexey Kuznetsov <[email protected]>
    Signed-off-by: Dmitry Monakhov <[email protected]>
---
 fs/fuse/file.c                     |   1 +
 fs/fuse/kio/pcs/fuse_io.c          |  42 +++++++-
 fs/fuse/kio/pcs/pcs_cluster.c      | 207 +++++++++++++++++++++++++++++++++++++
 fs/fuse/kio/pcs/pcs_cluster.h      |   2 +-
 fs/fuse/kio/pcs/pcs_cs.c           |  22 +++-
 fs/fuse/kio/pcs/pcs_fuse_kdirect.c |  63 ++++++++---
 fs/fuse/kio/pcs/pcs_map.c          |  28 +++--
 fs/fuse/kio/pcs/pcs_req.c          |   6 ++
 fs/fuse/kio/pcs/pcs_req.h          |   1 +
 9 files changed, 344 insertions(+), 28 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 43733920fd7e..d84dd402c83c 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -3794,6 +3794,7 @@ static int fuse_request_fiemap(struct inode *inode, u32 
cur_max,
        if (IS_ERR(req))
                return PTR_ERR(req);
 
+       req->io_inode = inode;
        req->in.h.opcode = FUSE_IOCTL;
        req->in.h.nodeid = get_node_id(inode);
 
diff --git a/fs/fuse/kio/pcs/fuse_io.c b/fs/fuse/kio/pcs/fuse_io.c
index 47950d26757f..65c4a1881d89 100644
--- a/fs/fuse/kio/pcs/fuse_io.c
+++ b/fs/fuse/kio/pcs/fuse_io.c
@@ -84,6 +84,16 @@ static void on_fallocate_done(struct pcs_fuse_req *r, off_t 
pos, size_t size)
        request_end(pfc->fc, &r->req);
 }
 
+static void on_fiemap_done(struct pcs_fuse_req *r)
+{
+       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);
+
+       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;
@@ -92,6 +102,22 @@ static void req_get_iter(void *data, unsigned int offset, 
struct iov_iter *it)
        iov_iter_advance(it, offset);
 }
 
+static void req_fiemap_get_iter(void *data, unsigned int offset, struct 
iov_iter *it)
+{
+       struct pcs_fuse_req * r = data;
+       struct pcs_int_request *ireq = &r->exec.ireq;
+
+       if (offset < sizeof(struct fiemap)) {
+               iov_iter_init_plain(it, (char *)r->req.out.args[1].value,
+                                   sizeof(struct fiemap), 0);
+       } else {
+               offset -= sizeof(struct fiemap);
+               iov_iter_init_bvec(it, r->exec.io.bvec, r->exec.io.num_bvecs,
+                                  ireq->apireq.aux*sizeof(struct 
fiemap_extent), 0);
+       }
+       iov_iter_advance(it, offset);
+}
+
 static inline void set_io_buff(struct pcs_fuse_req *r, off_t offset, size_t 
size,
                               int is_bvec, int zeroing)
 {
@@ -126,7 +152,7 @@ static inline void set_io_buff(struct pcs_fuse_req *r, 
off_t offset, size_t size
        r->exec.io.req.size = size;
 }
 
-static void prepare_io_(struct pcs_fuse_req *r, unsigned short type, off_t 
offset, size_t size,
+static void prepare_io_(struct pcs_fuse_req *r, unsigned short type, off_t 
offset, size_t size, u64 aux,
                       void (*complete)(struct _pcs_api_iorequest_t *))
 {
        /* Use inline request structure */
@@ -150,6 +176,9 @@ static void prepare_io_(struct pcs_fuse_req *r, unsigned 
short type, off_t offse
                r->exec.io.req.pos = offset;
                r->exec.io.req.size = size;
                break;
+       case PCS_REQ_T_FIEMAP:
+               set_io_buff(r, offset, size, 0, 0);
+               break;
        }
 
        r->exec.io.req.type = type;
@@ -157,10 +186,14 @@ static void prepare_io_(struct pcs_fuse_req *r, unsigned 
short type, off_t offse
        r->exec.io.req.get_iter = req_get_iter;
        r->exec.io.req.complete = complete;
 
+       if (type == PCS_REQ_T_FIEMAP)
+               r->exec.io.req.get_iter = req_fiemap_get_iter;
+
        /* Initialize internal request structure */
        ireq->type = PCS_IREQ_API;
        ireq->ts = ktime_get();
        ireq->apireq.req = &r->exec.io.req;
+       ireq->apireq.aux = aux;
        ireq->complete_cb = intreq_complete;
        ireq->completion_data.parent = 0;
        ireq->completion_data.ctx = r;
@@ -196,15 +229,18 @@ static void ioreq_complete(pcs_api_iorequest_t *ioreq)
        case PCS_REQ_T_WRITE_ZERO:
                on_fallocate_done(r, ioreq->pos, ioreq->size);
                break;
+       case PCS_REQ_T_FIEMAP:
+               on_fiemap_done(r);
+               break;
        default:
                BUG();
        }
 
 }
 
-void pcs_fuse_prep_io(struct pcs_fuse_req *r, unsigned short type, off_t 
offset, size_t size)
+void pcs_fuse_prep_io(struct pcs_fuse_req *r, unsigned short type, off_t 
offset, size_t size, u64 aux)
 {
-       prepare_io_(r, type, offset, size, ioreq_complete);
+       prepare_io_(r, type, offset, size, aux, ioreq_complete);
 }
 
 static void falloc_req_complete(struct pcs_int_request *ireq)
diff --git a/fs/fuse/kio/pcs/pcs_cluster.c b/fs/fuse/kio/pcs/pcs_cluster.c
index 2d988484ec94..b995135a35cc 100644
--- a/fs/fuse/kio/pcs/pcs_cluster.c
+++ b/fs/fuse/kio/pcs/pcs_cluster.c
@@ -3,6 +3,7 @@
 #include <linux/kthread.h>
 #include <linux/types.h>
 #include <linux/rbtree.h>
+#include <linux/highmem.h>
 
 #include "pcs_types.h"
 #include "pcs_sock_io.h"
@@ -16,6 +17,8 @@
 
 #include "../../fuse_i.h"
 
+void pcs_cc_process_ireq_chunk(struct pcs_int_request *ireq);
+
 static inline int is_file_inline(struct pcs_dentry_info *di)
 {
        return di->fileinfo.attr.attrib & PCS_FATTR_INLINE;
@@ -75,6 +78,192 @@ void pcs_sreq_complete(struct pcs_int_request *sreq)
        ireq_destroy(sreq);
 }
 
+struct fiemap_iterator
+{
+       struct pcs_int_request  *orig_ireq;
+       wait_queue_head_t       wq;
+       char                    *buffer;
+       unsigned int            fiemap_max;
+       u32                     *mapped;
+
+       struct pcs_int_request  ireq;
+       pcs_api_iorequest_t     apireq;
+};
+
+static void fiemap_iter_done(struct pcs_int_request * ireq)
+{
+       struct fiemap_iterator * fiter = container_of(ireq, struct 
fiemap_iterator, ireq);
+
+       wake_up(&fiter->wq);
+}
+
+static void fiemap_get_iter(void * datasource, unsigned int offset, struct 
iov_iter *it)
+{
+       struct fiemap_iterator * iter = datasource;
+
+       BUG_ON(offset >= PCS_FIEMAP_BUFSIZE);
+       iov_iter_init_plain(it, iter->buffer, PCS_FIEMAP_BUFSIZE, 0);
+       iov_iter_advance(it, offset);
+}
+
+static void xfer_fiemap_extents(struct fiemap_iterator * iter, u64 pos, char * 
buffer, unsigned int count)
+{
+       struct pcs_cs_fiemap_rec * r = (struct pcs_cs_fiemap_rec *)buffer;
+
+       BUG_ON(count % sizeof(struct pcs_cs_fiemap_rec));
+       count /= sizeof(struct pcs_cs_fiemap_rec);
+
+       if (r[count - 1].flags & PCS_CS_FIEMAP_FL_OVFL) {
+               /* Adjust next scan pos in case of overflow, overwriting size */
+               u64 end = iter->apireq.pos + r[count - 1].offset + r[count - 
1].size;
+               if (end < pos + iter->apireq.size) {
+                       u64 adjusted_size = end - pos;
+                       if (adjusted_size < iter->apireq.size)
+                               iter->apireq.size = adjusted_size;
+               }
+       }
+
+       if (iter->fiemap_max == 0) {
+               *iter->mapped += count;
+       } else {
+               int i;
+
+               for (i = 0; i < count; i++) {
+                       struct fiemap_extent e;
+                       struct iov_iter it;
+                       void * buf;
+                       size_t len;
+
+                       if (*iter->mapped >= iter->fiemap_max)
+                               return;
+
+                       memset(&e, 0, sizeof(e));
+                       e.fe_logical = e.fe_physical = iter->apireq.pos + 
r[i].offset;
+                       e.fe_length = r[i].size;
+                       if (r[i].flags & PCS_CS_FIEMAP_FL_ZERO)
+                               e.fe_flags |= FIEMAP_EXTENT_UNWRITTEN;
+                       if (r[i].flags & PCS_CS_FIEMAP_FL_CACHE)
+                               e.fe_flags |= FIEMAP_EXTENT_DELALLOC;
+
+                       
iter->orig_ireq->apireq.req->get_iter(iter->orig_ireq->apireq.req->datasource,
+                                                             offsetof(struct 
fiemap, fm_extents) +
+                                                             *iter->mapped * 
sizeof(struct fiemap_extent),
+                                                             &it);
+                       iov_iter_truncate(&it, sizeof(e));
+
+                       iov_iter_kmap_atomic(&it, &buf, &len);
+                       memcpy(buf, &e, len);
+                       kunmap_atomic(buf);
+                       if (len != sizeof(e)) {
+                               size_t fraglen;
+                               iov_iter_advance(&it, len);
+                               iov_iter_kmap_atomic(&it, &buf, &fraglen);
+                               BUG_ON(len + fraglen != sizeof(e));
+                               memcpy(buf, (char*)&e + len, fraglen);
+                               kunmap_atomic(buf);
+                       }
+                       (*iter->mapped)++;
+               }
+       }
+}
+
+static int fiemap_worker(void * arg)
+{
+       struct pcs_int_request * orig_ireq = arg;
+       struct pcs_dentry_info * di;
+       struct fiemap_iterator * fiter;
+       struct iov_iter it;
+       u64 pos, end;
+
+       fiter = kmalloc(sizeof(struct fiemap_iterator), GFP_KERNEL);
+       if (fiter == NULL) {
+               pcs_set_local_error(&orig_ireq->error, PCS_ERR_NOMEM);
+               ireq_complete(orig_ireq);
+               return 0;
+       }
+
+       fiter->orig_ireq = orig_ireq;
+       init_waitqueue_head(&fiter->wq);
+       di = orig_ireq->dentry;
+       ireq_init(di, &fiter->ireq);
+       fiter->ireq.type = PCS_IREQ_API;
+       fiter->ireq.apireq.req = &fiter->apireq;
+       fiter->ireq.completion_data.parent = NULL;
+       fiter->ireq.complete_cb = fiemap_iter_done;
+       fiter->apireq.datasource = fiter;
+       fiter->apireq.get_iter = fiemap_get_iter;
+       fiter->apireq.complete = NULL;
+       fiter->buffer = kvmalloc(PCS_FIEMAP_BUFSIZE, GFP_KERNEL);
+       if (fiter->buffer == NULL) {
+               pcs_set_local_error(&orig_ireq->error, PCS_ERR_NOMEM);
+               ireq_complete(orig_ireq);
+               kfree(fiter);
+               return 0;
+       }
+       fiter->fiemap_max = orig_ireq->apireq.aux;
+       orig_ireq->apireq.req->get_iter(orig_ireq->apireq.req->datasource, 0, 
&it);
+       fiter->mapped = &((struct fiemap*)it.data)->fm_mapped_extents;
+
+       pos = fiter->orig_ireq->apireq.req->pos;
+       end = pos + fiter->orig_ireq->apireq.req->size;
+       while (pos < end) {
+               struct pcs_int_request * sreq;
+
+               if (fiter->fiemap_max && *fiter->mapped >= fiter->fiemap_max)
+                       break;
+
+               fiter->apireq.pos = pos;
+               fiter->apireq.size = end - pos;
+               fiter->ireq.ts = ktime_get();
+
+               sreq = ireq_alloc(di);
+               if (!sreq) {
+                       pcs_set_local_error(&orig_ireq->error, PCS_ERR_NOMEM);
+                       goto out;
+               }
+
+               atomic_set(&fiter->ireq.iocount, 0);
+
+               sreq->dentry = di;
+               sreq->type = PCS_IREQ_IOCHUNK;
+               sreq->iochunk.map = NULL;
+               sreq->iochunk.flow = pcs_flow_record(&di->mapping.ftab, 0, pos, 
end-pos, &di->cluster->maps.ftab);
+               sreq->iochunk.cmd = PCS_REQ_T_FIEMAP;
+               sreq->iochunk.cs_index = 0;
+               sreq->iochunk.chunk = pos;
+               sreq->iochunk.offset = 0;
+               sreq->iochunk.dio_offset = 0;
+               sreq->iochunk.size = end - pos;
+               sreq->iochunk.csl = NULL;
+               sreq->iochunk.banned_cs.val = 0;
+               sreq->iochunk.msg.destructor = NULL;
+               sreq->iochunk.msg.rpc = NULL;
+
+               pcs_sreq_attach(sreq, &fiter->ireq);
+               sreq->complete_cb = pcs_sreq_complete;
+
+               pcs_cc_process_ireq_chunk(sreq);
+
+               wait_event(fiter->wq, atomic_read(&fiter->ireq.iocount) == 0);
+
+               if (pcs_if_error(&fiter->ireq.error)) {
+                       fiter->orig_ireq->error = fiter->ireq.error;
+                       goto out;
+               }
+
+               if (fiter->ireq.apireq.aux)
+                       xfer_fiemap_extents(fiter, pos, fiter->buffer, 
fiter->ireq.apireq.aux);
+
+               pos += fiter->apireq.size;
+       }
+
+out:
+       kvfree(fiter->buffer);
+       kfree(fiter);
+       ireq_complete(orig_ireq);
+       return 0;
+}
+
 void pcs_cc_process_ireq_chunk(struct pcs_int_request *ireq)
 {
        struct pcs_map_entry *map;
@@ -167,12 +356,30 @@ static noinline void __pcs_cc_process_ireq_rw(struct 
pcs_int_request *ireq)
                ireq_complete(ireq);
 }
 
+static void process_ireq_fiemap(struct pcs_int_request * ireq)
+{
+       struct task_struct * tsk;
+
+       tsk = kthread_run(fiemap_worker, ireq, "fiemap-worker");
+
+       if (IS_ERR(tsk)) {
+               pcs_set_local_error(&ireq->error, PCS_ERR_NOMEM);
+               ireq_complete(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_FIEMAP) {
+               process_ireq_fiemap(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_HOLE &&
diff --git a/fs/fuse/kio/pcs/pcs_cluster.h b/fs/fuse/kio/pcs/pcs_cluster.h
index f1c20797d951..0f13345f919f 100644
--- a/fs/fuse/kio/pcs/pcs_cluster.h
+++ b/fs/fuse/kio/pcs/pcs_cluster.h
@@ -101,7 +101,7 @@ int pcs_cc_init(struct pcs_cluster_core *cc, struct 
workqueue_struct *wq,
                const char *cluster_name, struct pcs_cluster_core_attr *attr);
 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_io(struct pcs_fuse_req *r, unsigned short type, off_t 
offset, size_t size, u64 aux);
 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_cs.c b/fs/fuse/kio/pcs/pcs_cs.c
index 1fecaeaff16b..ba3c0fea5fe4 100644
--- a/fs/fuse/kio/pcs/pcs_cs.c
+++ b/fs/fuse/kio/pcs/pcs_cs.c
@@ -317,6 +317,7 @@ void pcs_cs_update_stat(struct pcs_cs *cs, u32 iolat, u32 
netlat, int op_type)
 static void cs_response_done(struct pcs_msg *msg)
 {
        struct pcs_int_request *ireq = ireq_from_msg(msg);
+       unsigned int resp_size = 0;
 
        if (!pcs_if_error(&msg->error)) {
                struct pcs_cs_iohdr *h = (struct pcs_cs_iohdr 
*)msg_inline_head(msg->response);
@@ -324,6 +325,8 @@ static void cs_response_done(struct pcs_msg *msg)
                if (h->sync.misc & PCS_CS_IO_CACHED)
                        ireq->flags |= IREQ_F_CACHED;
 
+               resp_size = h->hdr.len - sizeof(struct pcs_cs_iohdr);
+
                pcs_map_verify_sync_state(ireq->dentry, ireq, msg);
        } else {
                TRACE(XID_FMT " IO error %d %lu : %llu:%u+%u\n", 
XID_ARGS(ireq->iochunk.hbuf.hdr.xid),
@@ -336,6 +339,10 @@ static void cs_response_done(struct pcs_msg *msg)
                pcs_rpc_put(msg->rpc);
                msg->rpc = NULL;
        }
+       if (ireq->type == PCS_IREQ_IOCHUNK && ireq->iochunk.cmd == 
PCS_REQ_T_FIEMAP) {
+               ireq->completion_data.parent->apireq.aux = resp_size;
+               ireq->completion_data.parent->apireq.req->pos = 
ireq->iochunk.chunk;
+       }
        ireq_complete(ireq);
 }
 
@@ -360,7 +367,7 @@ static void cs_get_read_response_iter(struct pcs_msg *msg, 
int offset, struct io
 
                        offset -= (unsigned int)sizeof(struct pcs_cs_iohdr);
                        ar->get_iter(ar->datasource, ireq->iochunk.dio_offset, 
it);
-                       iov_iter_truncate(it, ireq->iochunk.size);
+                       iov_iter_truncate(it, msg->size - sizeof(struct 
pcs_cs_iohdr));
                        iov_iter_advance(it, offset);
 
                        TRACE("return msg:%p->size:%d off:%d it_len:%ld\n\n", 
msg, msg->size, offset, iov_iter_count(it));
@@ -384,6 +391,7 @@ static struct pcs_msg *cs_get_hdr(struct pcs_rpc *ep, 
struct pcs_rpc_hdr *h)
 {
        struct pcs_msg *msg, *resp;
        struct pcs_rpc_hdr *req_h;
+       struct pcs_int_request *ireq;
 
        if (!RPC_IS_RESPONSE(h->type))
                return NULL;
@@ -401,6 +409,18 @@ static struct pcs_msg *cs_get_hdr(struct pcs_rpc *ep, 
struct pcs_rpc_hdr *h)
        if (req_h->type != (h->type & ~PCS_RPC_DIRECTION))
                return NULL;
 
+       ireq = msg->private2;
+       if (ireq->type != PCS_IREQ_IOCHUNK)
+               return NULL;
+       if (ireq->iochunk.cmd == PCS_REQ_T_READ) {
+               if (ireq->iochunk.size + sizeof(struct pcs_cs_iohdr) != 
msg->size)
+                       return NULL;
+       } else if (ireq->iochunk.cmd == PCS_REQ_T_FIEMAP) {
+               if (PCS_FIEMAP_BUFSIZE + sizeof(struct pcs_cs_iohdr) < 
msg->size)
+                       return NULL;
+       } else
+               return NULL;
+
        resp = pcs_rpc_alloc_input_msg(ep, sizeof(struct pcs_cs_iohdr));
        if (!resp)
                return NULL;
diff --git a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c 
b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
index 70a7b38e3692..c371fe0ef51f 100644
--- a/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
+++ b/fs/fuse/kio/pcs/pcs_fuse_kdirect.c
@@ -748,7 +748,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);
+               pcs_fuse_prep_io(r, PCS_REQ_T_READ, in->offset, size, 0);
        } else if (r->req.in.h.opcode == FUSE_WRITE) {
                struct fuse_write_in *in = &r->req.misc.write.in;
 
@@ -756,7 +756,26 @@ static int pcs_fuse_prep_rw(struct pcs_fuse_req *r)
                        wait_grow(r, di, in->offset + in->size);
                        ret = 1;
                }
-               pcs_fuse_prep_io(r, PCS_REQ_T_WRITE, in->offset, in->size);
+               pcs_fuse_prep_io(r, PCS_REQ_T_WRITE, in->offset, in->size, 0);
+       } else if (r->req.in.h.opcode == FUSE_IOCTL) {
+               size_t size;
+               struct fiemap const *in = r->req.in.args[1].value;
+               struct fiemap *out = r->req.out.args[1].value;
+
+               *out = *in;
+               out->fm_mapped_extents = 0;
+
+               size = in->fm_length;
+               if (in->fm_start + size > di->fileinfo.attr.size) {
+                       if (in->fm_start >= di->fileinfo.attr.size) {
+                               spin_unlock(&di->lock);
+                               return -1;
+                       }
+                       size = di->fileinfo.attr.size - in->fm_start;
+               }
+               pcs_fuse_prep_io(r, PCS_REQ_T_FIEMAP, in->fm_start, 
in->fm_extent_count*sizeof(struct fiemap_extent),
+                                in->fm_extent_count);
+               r->exec.io.req.size = size;
        } else {
                struct fuse_fallocate_in const *in = r->req.in.args[0].value;
 
@@ -766,9 +785,9 @@ static int pcs_fuse_prep_rw(struct pcs_fuse_req *r)
                }
 
                if (in->mode & FALLOC_FL_PUNCH_HOLE)
-                       pcs_fuse_prep_io(r, PCS_REQ_T_WRITE_HOLE, in->offset, 
in->length);
+                       pcs_fuse_prep_io(r, PCS_REQ_T_WRITE_HOLE, in->offset, 
in->length, 0);
                else if (in->mode & FALLOC_FL_ZERO_RANGE)
-                       pcs_fuse_prep_io(r, PCS_REQ_T_WRITE_ZERO, in->offset, 
in->length);
+                       pcs_fuse_prep_io(r, PCS_REQ_T_WRITE_ZERO, in->offset, 
in->length, 0);
                else {
                        if (ret) {
                                pcs_fuse_prep_fallocate(r);
@@ -846,8 +865,24 @@ static void pcs_fuse_submit(struct pcs_fuse_cluster *pfc, 
struct fuse_req *req,
                break;
        }
        case FUSE_FSYNC:
-               pcs_fuse_prep_io(r, PCS_REQ_T_SYNC, 0, 0);
+               pcs_fuse_prep_io(r, PCS_REQ_T_SYNC, 0, 0, 0);
                goto submit;
+       case FUSE_IOCTL: {
+               int ret;
+
+               if (pfc->fc->no_fiemap) {
+                       r->req.out.h.error = -EOPNOTSUPP;
+                       goto error;
+               }
+
+               ret = pcs_fuse_prep_rw(r);
+               if (!ret)
+                       goto submit;
+               if (ret > 0)
+                       /* Pended, nothing to do. */
+                       return;
+               break;
+       }
        }
        r->req.out.h.error = 0;
 error:
@@ -926,6 +961,7 @@ static int kpcs_req_send(struct fuse_conn* fc, struct 
fuse_req *req, bool bg, bo
 {
        struct pcs_fuse_cluster *pfc = (struct pcs_fuse_cluster*)fc->kio.ctx;
        struct fuse_inode *fi = get_fuse_inode(req->io_inode);
+
        if (!fc->initialized || fc->conn_error)
                return 1;
 
@@ -946,6 +982,10 @@ static int kpcs_req_send(struct fuse_conn* fc, struct 
fuse_req *req, bool bg, bo
                spin_unlock(&fc->lock);
                return 1;
        }
+
+       if (!fi || !fi->private)
+               return 1;
+
        switch (req->in.h.opcode) {
        case FUSE_SETATTR: {
                struct pcs_fuse_req *r = pcs_req_from_fuse(req);
@@ -953,10 +993,6 @@ static int kpcs_req_send(struct fuse_conn* fc, struct 
fuse_req *req, bool bg, bo
                struct pcs_dentry_info *di;
                int shrink = 0;
 
-               /* Skip speciall inodes */
-               if (!fi->private)
-                       return 1;
-
                if (!(inarg->valid & FATTR_SIZE))
                        return 1;
 
@@ -986,16 +1022,19 @@ static int kpcs_req_send(struct fuse_conn* fc, struct 
fuse_req *req, bool bg, bo
        case FUSE_WRITE:
        case FUSE_FSYNC:
        case FUSE_FALLOCATE:
-               fi = get_fuse_inode(req->io_inode);
-               if (!fi->private)
+               break;
+       case FUSE_IOCTL: {
+               struct fuse_ioctl_in const * inarg = req->in.args[0].value;
+
+               if (inarg->cmd != FS_IOC_FIEMAP)
                        return 1;
 
                break;
+       }
        default:
                return 1;
        }
 
-
        __clear_bit(FR_BACKGROUND, &req->flags);
        __clear_bit(FR_PENDING, &req->flags);
        /* request_end below will do fuse_put_request() */
diff --git a/fs/fuse/kio/pcs/pcs_map.c b/fs/fuse/kio/pcs/pcs_map.c
index 65b71c69ec8d..705743056462 100644
--- a/fs/fuse/kio/pcs/pcs_map.c
+++ b/fs/fuse/kio/pcs/pcs_map.c
@@ -2204,17 +2204,23 @@ void map_submit(struct pcs_map_entry * m, struct 
pcs_int_request *ireq, int requ
                        BUG_ON(ireq->iochunk.chunk != map_chunk_start(m));
                        BUG_ON(ireq->iochunk.offset != pos - 
ireq->iochunk.chunk);
                        if (ireq->iochunk.size > len) {
-                               struct pcs_int_request * sreq;
-
-                               sreq = pcs_ireq_split(ireq, len, 0);
-                               if (ireq->iochunk.map) {
-                                       pcs_map_put(ireq->iochunk.map);
-                                       ireq->iochunk.map = NULL;
+                               if (ireq->iochunk.cmd == PCS_REQ_T_FIEMAP) {
+                                       pcs_api_iorequest_t * ar = 
ireq->completion_data.parent->apireq.req;
+                                       ireq->iochunk.size = len;
+                                       ar->size = ireq->iochunk.size;
+                               } else {
+                                       struct pcs_int_request * sreq;
+
+                                       sreq = pcs_ireq_split(ireq, len, 0);
+                                       if (ireq->iochunk.map) {
+                                               pcs_map_put(ireq->iochunk.map);
+                                               ireq->iochunk.map = NULL;
+                                       }
+                                       ireq->iochunk.chunk = map_chunk_end(m);
+                                       ireq->iochunk.offset = 0;
+                                       pcs_cc_submit(ireq->dentry->cluster, 
ireq);
+                                       ireq = sreq;
                                }
-                               ireq->iochunk.chunk = map_chunk_end(m);
-                               ireq->iochunk.offset = 0;
-                               pcs_cc_submit(ireq->dentry->cluster, ireq);
-                               ireq = sreq;
                        }
                }
 
@@ -2549,7 +2555,7 @@ static int commit_sync_info(struct pcs_int_request *req,
        update_net_latency(csl, resp->rpc->peer_id, &h->sync, lat);
        max_iolat = h->sync.ts_io;
 
-       if (h->hdr.type != PCS_CS_READ_RESP) {
+       if (h->hdr.type != PCS_CS_READ_RESP && h->hdr.type != 
PCS_CS_FIEMAP_RESP) {
                struct pcs_cs_sync_resp * srec;
                lat = h->sync.ts_net;
                for (srec = (struct pcs_cs_sync_resp*)(h + 1);
diff --git a/fs/fuse/kio/pcs/pcs_req.c b/fs/fuse/kio/pcs/pcs_req.c
index f1c364fe5f00..a05f1e43c94c 100644
--- a/fs/fuse/kio/pcs/pcs_req.c
+++ b/fs/fuse/kio/pcs/pcs_req.c
@@ -89,6 +89,12 @@ void ireq_handle_hole(struct pcs_int_request *ireq)
        BUG_ON(ireq->type != PCS_IREQ_IOCHUNK);
        BUG_ON(pcs_req_direction(ireq->iochunk.cmd));
 
+       if (ireq->iochunk.cmd == PCS_REQ_T_FIEMAP) {
+               ireq->completion_data.parent->apireq.aux = 0;
+               ireq_complete(ireq);
+               return;
+       }
+
        len = ireq->iochunk.size;
        offset = 0;
        iov_iter_init_bad(&it);
diff --git a/fs/fuse/kio/pcs/pcs_req.h b/fs/fuse/kio/pcs/pcs_req.h
index bf603e0af414..fba74e9c4a56 100644
--- a/fs/fuse/kio/pcs/pcs_req.h
+++ b/fs/fuse/kio/pcs/pcs_req.h
@@ -150,6 +150,7 @@ struct pcs_int_request
                struct {
                        pcs_api_iorequest_t *   req;            /* Client 
request */
                        unsigned int            dio_offset;     /* MBZ */
+                       u64                     aux;
                        void*                   h;              /* API handle */
                } apireq;
 
_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to