Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
64bbf121b6 | ||
|
|
30dff8893f | ||
|
|
becf14a705 | ||
|
|
64388788c1 | ||
|
|
37653abe4b | ||
|
|
7c054c6f10 | ||
|
|
bb7709e824 | ||
|
|
ebeace5a2d | ||
|
|
a378789f10 | ||
|
|
1fe678e57b | ||
|
|
2e592a2f22 | ||
|
|
b92f644e3a | ||
|
|
890ea3dbc0 | ||
|
|
06630369bf | ||
|
|
b4740acf62 | ||
|
|
eae81bbda6 |
@@ -50,6 +50,7 @@ Vitastor поддерживает QEMU-драйвер, протоколы NBD и
|
|||||||
- Параметры
|
- Параметры
|
||||||
- [Общие](docs/config/common.ru.md)
|
- [Общие](docs/config/common.ru.md)
|
||||||
- [Сетевые](docs/config/network.ru.md)
|
- [Сетевые](docs/config/network.ru.md)
|
||||||
|
- [Клиентский код](docs/config/client.en.md)
|
||||||
- [Глобальные дисковые параметры](docs/config/layout-cluster.ru.md)
|
- [Глобальные дисковые параметры](docs/config/layout-cluster.ru.md)
|
||||||
- [Дисковые параметры OSD](docs/config/layout-osd.ru.md)
|
- [Дисковые параметры OSD](docs/config/layout-osd.ru.md)
|
||||||
- [Прочие параметры OSD](docs/config/osd.ru.md)
|
- [Прочие параметры OSD](docs/config/osd.ru.md)
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ Read more details below in the documentation.
|
|||||||
- Parameter Reference
|
- Parameter Reference
|
||||||
- [Common](docs/config/common.en.md)
|
- [Common](docs/config/common.en.md)
|
||||||
- [Network](docs/config/network.en.md)
|
- [Network](docs/config/network.en.md)
|
||||||
|
- [Client](docs/config/client.en.md)
|
||||||
- [Global Disk Layout](docs/config/layout-cluster.en.md)
|
- [Global Disk Layout](docs/config/layout-cluster.en.md)
|
||||||
- [OSD Disk Layout](docs/config/layout-osd.en.md)
|
- [OSD Disk Layout](docs/config/layout-osd.en.md)
|
||||||
- [OSD Runtime Parameters](docs/config/osd.en.md)
|
- [OSD Runtime Parameters](docs/config/osd.en.md)
|
||||||
|
|||||||
@@ -35,10 +35,13 @@ rules:
|
|||||||
verbs: ["get", "list", "watch"]
|
verbs: ["get", "list", "watch"]
|
||||||
- apiGroups: ["snapshot.storage.k8s.io"]
|
- apiGroups: ["snapshot.storage.k8s.io"]
|
||||||
resources: ["volumesnapshots"]
|
resources: ["volumesnapshots"]
|
||||||
verbs: ["get", "list"]
|
verbs: ["get", "list", "patch"]
|
||||||
|
- apiGroups: ["snapshot.storage.k8s.io"]
|
||||||
|
resources: ["volumesnapshots/status"]
|
||||||
|
verbs: ["get", "list", "patch"]
|
||||||
- apiGroups: ["snapshot.storage.k8s.io"]
|
- apiGroups: ["snapshot.storage.k8s.io"]
|
||||||
resources: ["volumesnapshotcontents"]
|
resources: ["volumesnapshotcontents"]
|
||||||
verbs: ["create", "get", "list", "watch", "update", "delete"]
|
verbs: ["create", "get", "list", "watch", "update", "delete", "patch"]
|
||||||
- apiGroups: ["snapshot.storage.k8s.io"]
|
- apiGroups: ["snapshot.storage.k8s.io"]
|
||||||
resources: ["volumesnapshotclasses"]
|
resources: ["volumesnapshotclasses"]
|
||||||
verbs: ["get", "list", "watch"]
|
verbs: ["get", "list", "watch"]
|
||||||
@@ -53,7 +56,7 @@ rules:
|
|||||||
verbs: ["get", "list", "watch"]
|
verbs: ["get", "list", "watch"]
|
||||||
- apiGroups: ["snapshot.storage.k8s.io"]
|
- apiGroups: ["snapshot.storage.k8s.io"]
|
||||||
resources: ["volumesnapshotcontents/status"]
|
resources: ["volumesnapshotcontents/status"]
|
||||||
verbs: ["update"]
|
verbs: ["update", "patch"]
|
||||||
- apiGroups: [""]
|
- apiGroups: [""]
|
||||||
resources: ["configmaps"]
|
resources: ["configmaps"]
|
||||||
verbs: ["get"]
|
verbs: ["get"]
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ metadata:
|
|||||||
name: csi-vitastor-provisioner
|
name: csi-vitastor-provisioner
|
||||||
spec:
|
spec:
|
||||||
replicas: 3
|
replicas: 3
|
||||||
|
strategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
rollingUpdate:
|
||||||
|
maxUnavailable: 1
|
||||||
|
maxSurge: 0
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: csi-vitastor-provisioner
|
app: csi-vitastor-provisioner
|
||||||
@@ -46,7 +51,7 @@ spec:
|
|||||||
priorityClassName: system-cluster-critical
|
priorityClassName: system-cluster-critical
|
||||||
containers:
|
containers:
|
||||||
- name: csi-provisioner
|
- name: csi-provisioner
|
||||||
image: k8s.gcr.io/sig-storage/csi-provisioner:v2.2.0
|
image: k8s.gcr.io/sig-storage/csi-provisioner:v3.0.0
|
||||||
args:
|
args:
|
||||||
- "--csi-address=$(ADDRESS)"
|
- "--csi-address=$(ADDRESS)"
|
||||||
- "--v=5"
|
- "--v=5"
|
||||||
|
|||||||
@@ -17,3 +17,4 @@ parameters:
|
|||||||
# multiple etcdUrls may be specified, delimited by comma
|
# multiple etcdUrls may be specified, delimited by comma
|
||||||
#etcdUrl: "http://192.168.7.2:2379"
|
#etcdUrl: "http://192.168.7.2:2379"
|
||||||
#etcdPrefix: "/vitastor"
|
#etcdPrefix: "/vitastor"
|
||||||
|
allowVolumeExpansion: true
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
apiVersion: snapshot.storage.k8s.io/v1
|
||||||
|
kind: VolumeSnapshotClass
|
||||||
|
metadata:
|
||||||
|
name: vitastor-snapclass
|
||||||
|
driver: csi.vitastor.io
|
||||||
|
deletionPolicy: Delete
|
||||||
|
parameters:
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: test-vitastor-clone
|
||||||
|
spec:
|
||||||
|
storageClassName: vitastor
|
||||||
|
dataSource:
|
||||||
|
name: snap1
|
||||||
|
kind: VolumeSnapshot
|
||||||
|
apiGroup: snapshot.storage.k8s.io
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 10Gi
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
apiVersion: snapshot.storage.k8s.io/v1
|
||||||
|
kind: VolumeSnapshot
|
||||||
|
metadata:
|
||||||
|
name: snap1
|
||||||
|
spec:
|
||||||
|
volumeSnapshotClassName: vitastor-snapclass
|
||||||
|
source:
|
||||||
|
persistentVolumeClaimName: test-vitastor-pvc
|
||||||
+2
-1
@@ -9,7 +9,8 @@ require (
|
|||||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb
|
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||||
google.golang.org/grpc v1.33.1
|
google.golang.org/grpc v1.33.1
|
||||||
k8s.io/klog v1.1.0
|
google.golang.org/protobuf v1.24.0
|
||||||
|
k8s.io/klog v1.0.0
|
||||||
k8s.io/utils v0.0.0-20210305010621-2afb4311ab10
|
k8s.io/utils v0.0.0-20210305010621-2afb4311ab10
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+17
-17
@@ -6,9 +6,9 @@ cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTj
|
|||||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||||
cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
|
cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
|
||||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||||
cloud.google.com/go/storage v1.1.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||||
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
|
||||||
@@ -25,14 +25,14 @@ github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbt
|
|||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
github.com/beorn7/perks v1.1.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
@@ -92,13 +92,13 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
|||||||
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.1.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||||
@@ -112,7 +112,7 @@ github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3i
|
|||||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hpcloud/tail v1.1.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
@@ -121,7 +121,7 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
|
|||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||||
github.com/kisielk/gotool v1.1.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
@@ -153,10 +153,10 @@ github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR
|
|||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pmezard/go-difflib v1.1.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.1.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
github.com/prometheus/client_golang v1.1.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
@@ -326,13 +326,13 @@ google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEG
|
|||||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.1.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.1.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||||
gopkg.in/check.v1 v1.1.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
gopkg.in/tomb.v1 v1.1.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
@@ -351,8 +351,8 @@ k8s.io/apimachinery v0.19.0/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlm
|
|||||||
k8s.io/client-go v0.19.0/go.mod h1:H9E/VT95blcFQnlyShFgnFT9ZnJOAceiUHM3MlRC+mU=
|
k8s.io/client-go v0.19.0/go.mod h1:H9E/VT95blcFQnlyShFgnFT9ZnJOAceiUHM3MlRC+mU=
|
||||||
k8s.io/component-base v0.19.0/go.mod h1:dKsY8BxkA+9dZIAh2aWJLL/UdASFDNtGYTCItL4LM7Y=
|
k8s.io/component-base v0.19.0/go.mod h1:dKsY8BxkA+9dZIAh2aWJLL/UdASFDNtGYTCItL4LM7Y=
|
||||||
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||||
k8s.io/klog v1.1.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
||||||
k8s.io/klog v1.1.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
||||||
k8s.io/klog/v2 v2.2.0 h1:XRvcwJozkgZ1UQJmfMGpvRthQHOvihEhYtDfAaxMz/A=
|
k8s.io/klog/v2 v2.2.0 h1:XRvcwJozkgZ1UQJmfMGpvRthQHOvihEhYtDfAaxMz/A=
|
||||||
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
|
||||||
|
|||||||
+228
-21
@@ -20,6 +20,7 @@ import (
|
|||||||
|
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
|
|
||||||
"github.com/container-storage-interface/spec/lib/go/csi"
|
"github.com/container-storage-interface/spec/lib/go/csi"
|
||||||
)
|
)
|
||||||
@@ -45,6 +46,7 @@ type InodeConfig struct
|
|||||||
ParentPool uint64 `json:"parent_pool,omitempty"`
|
ParentPool uint64 `json:"parent_pool,omitempty"`
|
||||||
ParentId uint64 `json:"parent_id,omitempty"`
|
ParentId uint64 `json:"parent_id,omitempty"`
|
||||||
Readonly bool `json:"readonly,omitempty"`
|
Readonly bool `json:"readonly,omitempty"`
|
||||||
|
CreateTs uint64 `json:"create_ts,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ControllerServer struct
|
type ControllerServer struct
|
||||||
@@ -178,27 +180,43 @@ func (cs *ControllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
|
|||||||
return nil, status.Error(codes.InvalidArgument, "no etcdUrl in storage class configuration and no etcd_address in vitastor.conf")
|
return nil, status.Error(codes.InvalidArgument, "no etcdUrl in storage class configuration and no etcd_address in vitastor.conf")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
args := []string{ "create", volName, "-s", fmt.Sprintf("%v", volSize), "--pool", fmt.Sprintf("%v", poolId) }
|
||||||
|
|
||||||
|
// Support creation from snapshot
|
||||||
|
var src *csi.VolumeContentSource
|
||||||
|
if (req.VolumeContentSource.GetSnapshot() != nil)
|
||||||
|
{
|
||||||
|
snapId := req.VolumeContentSource.GetSnapshot().GetSnapshotId()
|
||||||
|
if (snapId != "")
|
||||||
|
{
|
||||||
|
snapVars := make(map[string]string)
|
||||||
|
err := json.Unmarshal([]byte(snapId), &snapVars)
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, status.Error(codes.Internal, "volume ID not in JSON format")
|
||||||
|
}
|
||||||
|
args = append(args, "--parent", snapVars["name"]+"@"+snapVars["snapshot"])
|
||||||
|
src = &csi.VolumeContentSource{
|
||||||
|
Type: &csi.VolumeContentSource_Snapshot{
|
||||||
|
Snapshot: &csi.VolumeContentSource_SnapshotSource{
|
||||||
|
SnapshotId: snapId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create image using vitastor-cli
|
// Create image using vitastor-cli
|
||||||
_, err := invokeCLI(ctxVars, []string{ "create", volName, "-s", fmt.Sprintf("%v", volSize), "--pool", fmt.Sprintf("%v", poolId) })
|
_, err := invokeCLI(ctxVars, args)
|
||||||
if (err != nil)
|
if (err != nil)
|
||||||
{
|
{
|
||||||
if (strings.Index(err.Error(), "already exists") > 0)
|
if (strings.Index(err.Error(), "already exists") > 0)
|
||||||
{
|
{
|
||||||
stat, err := invokeCLI(ctxVars, []string{ "ls", "--json", volName })
|
inodeCfg, err := invokeList(ctxVars, volName, true)
|
||||||
if (err != nil)
|
if (err != nil)
|
||||||
{
|
{
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var inodeCfg []InodeConfig
|
|
||||||
err = json.Unmarshal(stat, &inodeCfg)
|
|
||||||
if (err != nil)
|
|
||||||
{
|
|
||||||
return nil, status.Error(codes.Internal, "Invalid JSON in vitastor-cli ls: "+err.Error())
|
|
||||||
}
|
|
||||||
if (len(inodeCfg) == 0)
|
|
||||||
{
|
|
||||||
return nil, status.Error(codes.Internal, "vitastor-cli create said that image already exists, but ls can't find it")
|
|
||||||
}
|
|
||||||
if (inodeCfg[0].Size < uint64(volSize))
|
if (inodeCfg[0].Size < uint64(volSize))
|
||||||
{
|
{
|
||||||
return nil, status.Error(codes.Internal, "image "+volName+" is already created, but size is less than expected")
|
return nil, status.Error(codes.Internal, "image "+volName+" is already created, but size is less than expected")
|
||||||
@@ -217,6 +235,7 @@ func (cs *ControllerServer) CreateVolume(ctx context.Context, req *csi.CreateVol
|
|||||||
// Ugly, but VolumeContext isn't passed to DeleteVolume :-(
|
// Ugly, but VolumeContext isn't passed to DeleteVolume :-(
|
||||||
VolumeId: string(volumeIdJson),
|
VolumeId: string(volumeIdJson),
|
||||||
CapacityBytes: volSize,
|
CapacityBytes: volSize,
|
||||||
|
ContentSource: src,
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -230,15 +249,15 @@ func (cs *ControllerServer) DeleteVolume(ctx context.Context, req *csi.DeleteVol
|
|||||||
return nil, status.Error(codes.InvalidArgument, "request cannot be empty")
|
return nil, status.Error(codes.InvalidArgument, "request cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctxVars := make(map[string]string)
|
volVars := make(map[string]string)
|
||||||
err := json.Unmarshal([]byte(req.VolumeId), &ctxVars)
|
err := json.Unmarshal([]byte(req.VolumeId), &volVars)
|
||||||
if (err != nil)
|
if (err != nil)
|
||||||
{
|
{
|
||||||
return nil, status.Error(codes.Internal, "volume ID not in JSON format")
|
return nil, status.Error(codes.Internal, "volume ID not in JSON format")
|
||||||
}
|
}
|
||||||
volName := ctxVars["name"]
|
volName := volVars["name"]
|
||||||
|
|
||||||
ctxVars, _, _ = GetConnectionParams(ctxVars)
|
ctxVars, _, _ := GetConnectionParams(volVars)
|
||||||
|
|
||||||
_, err = invokeCLI(ctxVars, []string{ "rm", volName })
|
_, err = invokeCLI(ctxVars, []string{ "rm", volName })
|
||||||
if (err != nil)
|
if (err != nil)
|
||||||
@@ -344,6 +363,8 @@ func (cs *ControllerServer) ControllerGetCapabilities(ctx context.Context, req *
|
|||||||
csi.ControllerServiceCapability_RPC_LIST_VOLUMES,
|
csi.ControllerServiceCapability_RPC_LIST_VOLUMES,
|
||||||
csi.ControllerServiceCapability_RPC_EXPAND_VOLUME,
|
csi.ControllerServiceCapability_RPC_EXPAND_VOLUME,
|
||||||
csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT,
|
csi.ControllerServiceCapability_RPC_CREATE_DELETE_SNAPSHOT,
|
||||||
|
csi.ControllerServiceCapability_RPC_LIST_SNAPSHOTS,
|
||||||
|
// TODO: csi.ControllerServiceCapability_RPC_CLONE_VOLUME,
|
||||||
} {
|
} {
|
||||||
controllerServerCapabilities = append(controllerServerCapabilities, functionControllerServerCapabilities(capability))
|
controllerServerCapabilities = append(controllerServerCapabilities, functionControllerServerCapabilities(capability))
|
||||||
}
|
}
|
||||||
@@ -353,28 +374,214 @@ func (cs *ControllerServer) ControllerGetCapabilities(ctx context.Context, req *
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func invokeList(ctxVars map[string]string, pattern string, expectExist bool) ([]InodeConfig, error)
|
||||||
|
{
|
||||||
|
stat, err := invokeCLI(ctxVars, []string{ "ls", "--json", pattern })
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var inodeCfg []InodeConfig
|
||||||
|
err = json.Unmarshal(stat, &inodeCfg)
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, status.Error(codes.Internal, "Invalid JSON in vitastor-cli ls: "+err.Error())
|
||||||
|
}
|
||||||
|
if (expectExist && len(inodeCfg) == 0)
|
||||||
|
{
|
||||||
|
return nil, status.Error(codes.Internal, "Can't find expected image "+pattern+" via vitastor-cli ls")
|
||||||
|
}
|
||||||
|
return inodeCfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
// CreateSnapshot create snapshot of an existing PV
|
// CreateSnapshot create snapshot of an existing PV
|
||||||
func (cs *ControllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error)
|
func (cs *ControllerServer) CreateSnapshot(ctx context.Context, req *csi.CreateSnapshotRequest) (*csi.CreateSnapshotResponse, error)
|
||||||
{
|
{
|
||||||
return nil, status.Error(codes.Unimplemented, "")
|
klog.Infof("received controller create snapshot request %+v", protosanitizer.StripSecrets(req))
|
||||||
|
if (req == nil)
|
||||||
|
{
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, "request cannot be empty")
|
||||||
|
}
|
||||||
|
if (req.SourceVolumeId == "" || req.Name == "")
|
||||||
|
{
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "source volume ID and snapshot name are required fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
// snapshot name
|
||||||
|
snapName := req.Name
|
||||||
|
|
||||||
|
// req.VolumeId is an ugly json string in our case :)
|
||||||
|
ctxVars := make(map[string]string)
|
||||||
|
err := json.Unmarshal([]byte(req.SourceVolumeId), &ctxVars)
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, status.Error(codes.Internal, "volume ID not in JSON format")
|
||||||
|
}
|
||||||
|
volName := ctxVars["name"]
|
||||||
|
|
||||||
|
// Create image using vitastor-cli
|
||||||
|
_, err = invokeCLI(ctxVars, []string{ "create", "--snapshot", snapName, volName })
|
||||||
|
if (err != nil && strings.Index(err.Error(), "already exists") <= 0)
|
||||||
|
{
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check created snapshot
|
||||||
|
inodeCfg, err := invokeList(ctxVars, volName+"@"+snapName, true)
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use ugly JSON snapshot ID again, DeleteSnapshot doesn't have context :-(
|
||||||
|
ctxVars["snapshot"] = snapName
|
||||||
|
snapIdJson, _ := json.Marshal(ctxVars)
|
||||||
|
return &csi.CreateSnapshotResponse{
|
||||||
|
Snapshot: &csi.Snapshot{
|
||||||
|
SizeBytes: int64(inodeCfg[0].Size),
|
||||||
|
SnapshotId: string(snapIdJson),
|
||||||
|
SourceVolumeId: req.SourceVolumeId,
|
||||||
|
CreationTime: ×tamppb.Timestamp{ Seconds: int64(inodeCfg[0].CreateTs) },
|
||||||
|
ReadyToUse: true,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteSnapshot delete provided snapshot of a PV
|
// DeleteSnapshot delete provided snapshot of a PV
|
||||||
func (cs *ControllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error)
|
func (cs *ControllerServer) DeleteSnapshot(ctx context.Context, req *csi.DeleteSnapshotRequest) (*csi.DeleteSnapshotResponse, error)
|
||||||
{
|
{
|
||||||
return nil, status.Error(codes.Unimplemented, "")
|
klog.Infof("received controller delete snapshot request %+v", protosanitizer.StripSecrets(req))
|
||||||
|
if (req == nil)
|
||||||
|
{
|
||||||
|
return nil, status.Errorf(codes.InvalidArgument, "request cannot be empty")
|
||||||
|
}
|
||||||
|
if (req.SnapshotId == "")
|
||||||
|
{
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "snapshot ID is a required field")
|
||||||
|
}
|
||||||
|
|
||||||
|
volVars := make(map[string]string)
|
||||||
|
err := json.Unmarshal([]byte(req.SnapshotId), &volVars)
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, status.Error(codes.Internal, "snapshot ID not in JSON format")
|
||||||
|
}
|
||||||
|
volName := volVars["name"]
|
||||||
|
snapName := volVars["snapshot"]
|
||||||
|
|
||||||
|
ctxVars, _, _ := GetConnectionParams(volVars)
|
||||||
|
|
||||||
|
_, err = invokeCLI(ctxVars, []string{ "rm", volName+"@"+snapName })
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &csi.DeleteSnapshotResponse{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListSnapshots list the snapshots of a PV
|
// ListSnapshots list the snapshots of a PV
|
||||||
func (cs *ControllerServer) ListSnapshots(ctx context.Context, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error)
|
func (cs *ControllerServer) ListSnapshots(ctx context.Context, req *csi.ListSnapshotsRequest) (*csi.ListSnapshotsResponse, error)
|
||||||
{
|
{
|
||||||
return nil, status.Error(codes.Unimplemented, "")
|
klog.Infof("received controller list snapshots request %+v", protosanitizer.StripSecrets(req))
|
||||||
|
if (req == nil)
|
||||||
|
{
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "request cannot be empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
volVars := make(map[string]string)
|
||||||
|
err := json.Unmarshal([]byte(req.SourceVolumeId), &volVars)
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, status.Error(codes.Internal, "volume ID not in JSON format")
|
||||||
|
}
|
||||||
|
volName := volVars["name"]
|
||||||
|
ctxVars, _, _ := GetConnectionParams(volVars)
|
||||||
|
|
||||||
|
inodeCfg, err := invokeList(ctxVars, volName+"@*", false)
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := &csi.ListSnapshotsResponse{}
|
||||||
|
for _, ino := range inodeCfg
|
||||||
|
{
|
||||||
|
snapName := ino.Name[len(volName)+1:]
|
||||||
|
if (len(req.StartingToken) > 0 && snapName < req.StartingToken)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else if (req.MaxEntries == 0 || len(resp.Entries) < int(req.MaxEntries))
|
||||||
|
{
|
||||||
|
volVars["snapshot"] = snapName
|
||||||
|
snapIdJson, _ := json.Marshal(volVars)
|
||||||
|
resp.Entries = append(resp.Entries, &csi.ListSnapshotsResponse_Entry{
|
||||||
|
Snapshot: &csi.Snapshot{
|
||||||
|
SizeBytes: int64(ino.Size),
|
||||||
|
SnapshotId: string(snapIdJson),
|
||||||
|
SourceVolumeId: req.SourceVolumeId,
|
||||||
|
CreationTime: ×tamppb.Timestamp{ Seconds: int64(ino.CreateTs) },
|
||||||
|
ReadyToUse: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resp.NextToken = snapName
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ControllerExpandVolume resizes a volume
|
// ControllerExpandVolume increases the size of a volume
|
||||||
func (cs *ControllerServer) ControllerExpandVolume(ctx context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error)
|
func (cs *ControllerServer) ControllerExpandVolume(ctx context.Context, req *csi.ControllerExpandVolumeRequest) (*csi.ControllerExpandVolumeResponse, error)
|
||||||
{
|
{
|
||||||
return nil, status.Error(codes.Unimplemented, "")
|
klog.Infof("received controller expand volume request %+v", protosanitizer.StripSecrets(req))
|
||||||
|
if (req == nil)
|
||||||
|
{
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "request cannot be empty")
|
||||||
|
}
|
||||||
|
if (req.VolumeId == "" || req.CapacityRange == nil || req.CapacityRange.RequiredBytes == 0)
|
||||||
|
{
|
||||||
|
return nil, status.Error(codes.InvalidArgument, "VolumeId, CapacityRange and RequiredBytes are required fields")
|
||||||
|
}
|
||||||
|
|
||||||
|
volVars := make(map[string]string)
|
||||||
|
err := json.Unmarshal([]byte(req.VolumeId), &volVars)
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, status.Error(codes.Internal, "volume ID not in JSON format")
|
||||||
|
}
|
||||||
|
volName := volVars["name"]
|
||||||
|
ctxVars, _, _ := GetConnectionParams(volVars)
|
||||||
|
|
||||||
|
inodeCfg, err := invokeList(ctxVars, volName, true)
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.CapacityRange.RequiredBytes > 0 && inodeCfg[0].Size < uint64(req.CapacityRange.RequiredBytes))
|
||||||
|
{
|
||||||
|
sz := ((req.CapacityRange.RequiredBytes+4095)/4096)*4096
|
||||||
|
_, err := invokeCLI(ctxVars, []string{ "modify", "--inc_size", "1", "--resize", fmt.Sprintf("%d", sz), volName })
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
inodeCfg, err = invokeList(ctxVars, volName, true)
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &csi.ControllerExpandVolumeResponse{
|
||||||
|
CapacityBytes: int64(inodeCfg[0].Size),
|
||||||
|
NodeExpansionRequired: false,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ControllerGetVolume get volume info
|
// ControllerGetVolume get volume info
|
||||||
|
|||||||
@@ -49,6 +49,13 @@ func (is *IdentityServer) GetPluginCapabilities(ctx context.Context, req *csi.Ge
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Type: &csi.PluginCapability_VolumeExpansion_{
|
||||||
|
VolumeExpansion: &csi.PluginCapability_VolumeExpansion{
|
||||||
|
Type: csi.PluginCapability_VolumeExpansion_OFFLINE,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
+76
-69
@@ -70,10 +70,10 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
|
|||||||
isBlock := req.GetVolumeCapability().GetBlock() != nil
|
isBlock := req.GetVolumeCapability().GetBlock() != nil
|
||||||
|
|
||||||
// Check that it's not already mounted
|
// Check that it's not already mounted
|
||||||
_, error := mount.IsNotMountPoint(ns.mounter, targetPath)
|
_, err := mount.IsNotMountPoint(ns.mounter, targetPath)
|
||||||
if (error != nil)
|
if (err != nil)
|
||||||
{
|
{
|
||||||
if (os.IsNotExist(error))
|
if (os.IsNotExist(err))
|
||||||
{
|
{
|
||||||
if (isBlock)
|
if (isBlock)
|
||||||
{
|
{
|
||||||
@@ -102,12 +102,12 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return nil, status.Error(codes.Internal, error.Error())
|
return nil, status.Error(codes.Internal, err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctxVars := make(map[string]string)
|
ctxVars := make(map[string]string)
|
||||||
err := json.Unmarshal([]byte(req.VolumeId), &ctxVars)
|
err = json.Unmarshal([]byte(req.VolumeId), &ctxVars)
|
||||||
if (err != nil)
|
if (err != nil)
|
||||||
{
|
{
|
||||||
return nil, status.Error(codes.Internal, "volume ID not in JSON format")
|
return nil, status.Error(codes.Internal, "volume ID not in JSON format")
|
||||||
@@ -147,70 +147,74 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
|
|||||||
}
|
}
|
||||||
devicePath := strings.TrimSpace(stdoutStr)
|
devicePath := strings.TrimSpace(stdoutStr)
|
||||||
|
|
||||||
// Check existing format
|
|
||||||
diskMounter := &mount.SafeFormatAndMount{Interface: ns.mounter, Exec: utilexec.New()}
|
diskMounter := &mount.SafeFormatAndMount{Interface: ns.mounter, Exec: utilexec.New()}
|
||||||
existingFormat, err := diskMounter.GetDiskFormat(devicePath)
|
|
||||||
if (err != nil)
|
|
||||||
{
|
|
||||||
klog.Errorf("failed to get disk format for path %s, error: %v", err)
|
|
||||||
// unmap NBD device
|
|
||||||
unmapOut, unmapErr := exec.Command("/usr/bin/vitastor-nbd", "unmap", devicePath).CombinedOutput()
|
|
||||||
if (unmapErr != nil)
|
|
||||||
{
|
|
||||||
klog.Errorf("failed to unmap NBD device %s: %s, error: %v", devicePath, unmapOut, unmapErr)
|
|
||||||
}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Format the device (ext4 or xfs)
|
|
||||||
fsType := req.GetVolumeCapability().GetMount().GetFsType()
|
|
||||||
opt := req.GetVolumeCapability().GetMount().GetMountFlags()
|
|
||||||
opt = append(opt, "_netdev")
|
|
||||||
if ((req.VolumeCapability.AccessMode.Mode == csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY ||
|
|
||||||
req.VolumeCapability.AccessMode.Mode == csi.VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY) &&
|
|
||||||
!Contains(opt, "ro"))
|
|
||||||
{
|
|
||||||
opt = append(opt, "ro")
|
|
||||||
}
|
|
||||||
if (fsType == "xfs")
|
|
||||||
{
|
|
||||||
opt = append(opt, "nouuid")
|
|
||||||
}
|
|
||||||
readOnly := Contains(opt, "ro")
|
|
||||||
if (existingFormat == "" && !readOnly)
|
|
||||||
{
|
|
||||||
args := []string{}
|
|
||||||
switch fsType
|
|
||||||
{
|
|
||||||
case "ext4":
|
|
||||||
args = []string{"-m0", "-Enodiscard,lazy_itable_init=1,lazy_journal_init=1", devicePath}
|
|
||||||
case "xfs":
|
|
||||||
args = []string{"-K", devicePath}
|
|
||||||
}
|
|
||||||
if (len(args) > 0)
|
|
||||||
{
|
|
||||||
cmdOut, cmdErr := diskMounter.Exec.Command("mkfs."+fsType, args...).CombinedOutput()
|
|
||||||
if (cmdErr != nil)
|
|
||||||
{
|
|
||||||
klog.Errorf("failed to run mkfs error: %v, output: %v", cmdErr, string(cmdOut))
|
|
||||||
// unmap NBD device
|
|
||||||
unmapOut, unmapErr := exec.Command("/usr/bin/vitastor-nbd", "unmap", devicePath).CombinedOutput()
|
|
||||||
if (unmapErr != nil)
|
|
||||||
{
|
|
||||||
klog.Errorf("failed to unmap NBD device %s: %s, error: %v", devicePath, unmapOut, unmapErr)
|
|
||||||
}
|
|
||||||
return nil, status.Error(codes.Internal, cmdErr.Error())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isBlock)
|
if (isBlock)
|
||||||
{
|
{
|
||||||
opt = append(opt, "bind")
|
err = diskMounter.Mount(devicePath, targetPath, "", []string{"bind"})
|
||||||
err = diskMounter.Mount(devicePath, targetPath, fsType, opt)
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Check existing format
|
||||||
|
existingFormat, err := diskMounter.GetDiskFormat(devicePath)
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
klog.Errorf("failed to get disk format for path %s, error: %v", err)
|
||||||
|
goto unmap
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format the device (ext4 or xfs)
|
||||||
|
fsType := req.GetVolumeCapability().GetMount().GetFsType()
|
||||||
|
opt := req.GetVolumeCapability().GetMount().GetMountFlags()
|
||||||
|
opt = append(opt, "_netdev")
|
||||||
|
if ((req.VolumeCapability.AccessMode.Mode == csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY ||
|
||||||
|
req.VolumeCapability.AccessMode.Mode == csi.VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY) &&
|
||||||
|
!Contains(opt, "ro"))
|
||||||
|
{
|
||||||
|
opt = append(opt, "ro")
|
||||||
|
}
|
||||||
|
if (fsType == "xfs")
|
||||||
|
{
|
||||||
|
opt = append(opt, "nouuid")
|
||||||
|
}
|
||||||
|
readOnly := Contains(opt, "ro")
|
||||||
|
if (existingFormat == "" && !readOnly)
|
||||||
|
{
|
||||||
|
var cmdOut []byte
|
||||||
|
switch fsType
|
||||||
|
{
|
||||||
|
case "ext4":
|
||||||
|
args := []string{"-m0", "-Enodiscard,lazy_itable_init=1,lazy_journal_init=1", devicePath}
|
||||||
|
cmdOut, err = diskMounter.Exec.Command("mkfs.ext4", args...).CombinedOutput()
|
||||||
|
case "xfs":
|
||||||
|
cmdOut, err = diskMounter.Exec.Command("mkfs.xfs", "-K", devicePath).CombinedOutput()
|
||||||
|
}
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
klog.Errorf("failed to run mkfs error: %v, output: %v", err, string(cmdOut))
|
||||||
|
goto unmap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err = diskMounter.FormatAndMount(devicePath, targetPath, fsType, opt)
|
err = diskMounter.FormatAndMount(devicePath, targetPath, fsType, opt)
|
||||||
|
|
||||||
|
// Try to run online resize on mount.
|
||||||
|
// FIXME: Implement online resize. It requires online resize support in vitastor-nbd.
|
||||||
|
if (err == nil && existingFormat != "" && !readOnly)
|
||||||
|
{
|
||||||
|
var cmdOut []byte
|
||||||
|
switch (fsType)
|
||||||
|
{
|
||||||
|
case "ext4":
|
||||||
|
cmdOut, err = diskMounter.Exec.Command("resize2fs", devicePath).CombinedOutput()
|
||||||
|
case "xfs":
|
||||||
|
cmdOut, err = diskMounter.Exec.Command("xfs_growfs", devicePath).CombinedOutput()
|
||||||
|
}
|
||||||
|
if (err != nil)
|
||||||
|
{
|
||||||
|
klog.Errorf("failed to run resizefs error: %v, output: %v", err, string(cmdOut))
|
||||||
|
goto unmap
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (err != nil)
|
if (err != nil)
|
||||||
{
|
{
|
||||||
@@ -218,15 +222,18 @@ func (ns *NodeServer) NodePublishVolume(ctx context.Context, req *csi.NodePublis
|
|||||||
"failed to mount device path (%s) to path (%s) for volume (%s) error: %s",
|
"failed to mount device path (%s) to path (%s) for volume (%s) error: %s",
|
||||||
devicePath, targetPath, volName, err,
|
devicePath, targetPath, volName, err,
|
||||||
)
|
)
|
||||||
// unmap NBD device
|
goto unmap
|
||||||
unmapOut, unmapErr := exec.Command("/usr/bin/vitastor-nbd", "unmap", devicePath).CombinedOutput()
|
|
||||||
if (unmapErr != nil)
|
|
||||||
{
|
|
||||||
klog.Errorf("failed to unmap NBD device %s: %s, error: %v", devicePath, unmapOut, unmapErr)
|
|
||||||
}
|
|
||||||
return nil, status.Error(codes.Internal, err.Error())
|
|
||||||
}
|
}
|
||||||
return &csi.NodePublishVolumeResponse{}, nil
|
return &csi.NodePublishVolumeResponse{}, nil
|
||||||
|
|
||||||
|
unmap:
|
||||||
|
// unmap NBD device
|
||||||
|
unmapOut, unmapErr := exec.Command("/usr/bin/vitastor-nbd", "unmap", devicePath).CombinedOutput()
|
||||||
|
if (unmapErr != nil)
|
||||||
|
{
|
||||||
|
klog.Errorf("failed to unmap NBD device %s: %s, error: %v", devicePath, unmapOut, unmapErr)
|
||||||
|
}
|
||||||
|
return nil, status.Error(codes.Internal, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// NodeUnpublishVolume unmounts the volume from the target path
|
// NodeUnpublishVolume unmounts the volume from the target path
|
||||||
|
|||||||
Vendored
+1
-1
@@ -2,7 +2,7 @@ Source: vitastor
|
|||||||
Section: admin
|
Section: admin
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: Vitaliy Filippov <vitalif@yourcmc.ru>
|
Maintainer: Vitaliy Filippov <vitalif@yourcmc.ru>
|
||||||
Build-Depends: debhelper, liburing-dev (>= 0.6), g++ (>= 8), libstdc++6 (>= 8), linux-libc-dev, libgoogle-perftools-dev, libjerasure-dev, libgf-complete-dev, libibverbs-dev, libisal-dev
|
Build-Depends: debhelper, liburing-dev (>= 0.6), g++ (>= 8), libstdc++6 (>= 8), linux-libc-dev, libgoogle-perftools-dev, libjerasure-dev, libgf-complete-dev, libibverbs-dev, libisal-dev, cmake, pkg-config
|
||||||
Standards-Version: 4.5.0
|
Standards-Version: 4.5.0
|
||||||
Homepage: https://vitastor.io/
|
Homepage: https://vitastor.io/
|
||||||
Rules-Requires-Root: no
|
Rules-Requires-Root: no
|
||||||
|
|||||||
@@ -67,8 +67,8 @@
|
|||||||
явно не разрешена клиентом, т.к. если клиент не знает, что запросы записи
|
явно не разрешена клиентом, т.к. если клиент не знает, что запросы записи
|
||||||
буферизуются, это может приводить к потере данных. Поэтому в старых версиях
|
буферизуются, это может приводить к потере данных. Поэтому в старых версиях
|
||||||
клиентских драйверов буферизация записи не включается вообще, в новых
|
клиентских драйверов буферизация записи не включается вообще, в новых
|
||||||
версиях QEMU-драйвера включается только если разрешена опцией диска
|
версиях QEMU-драйвера включается, только если разрешена опцией диска
|
||||||
`-blockdev cache.direct=false`, а в fio - только если нет опция `-direct=1`.
|
`-blockdev cache.direct=false`, а в fio - только если нет опции `-direct=1`.
|
||||||
В NBD и NFS драйверах буферизация записи разрешена по умолчанию.
|
В NBD и NFS драйверах буферизация записи разрешена по умолчанию.
|
||||||
|
|
||||||
Можно обойти и это ограничение с помощью параметра `client_writeback_allowed`,
|
Можно обойти и это ограничение с помощью параметра `client_writeback_allowed`,
|
||||||
|
|||||||
@@ -87,8 +87,8 @@
|
|||||||
явно не разрешена клиентом, т.к. если клиент не знает, что запросы записи
|
явно не разрешена клиентом, т.к. если клиент не знает, что запросы записи
|
||||||
буферизуются, это может приводить к потере данных. Поэтому в старых версиях
|
буферизуются, это может приводить к потере данных. Поэтому в старых версиях
|
||||||
клиентских драйверов буферизация записи не включается вообще, в новых
|
клиентских драйверов буферизация записи не включается вообще, в новых
|
||||||
версиях QEMU-драйвера включается только если разрешена опцией диска
|
версиях QEMU-драйвера включается, только если разрешена опцией диска
|
||||||
`-blockdev cache.direct=false`, а в fio - только если нет опция `-direct=1`.
|
`-blockdev cache.direct=false`, а в fio - только если нет опции `-direct=1`.
|
||||||
В NBD и NFS драйверах буферизация записи разрешена по умолчанию.
|
В NBD и NFS драйверах буферизация записи разрешена по умолчанию.
|
||||||
|
|
||||||
Можно обойти и это ограничение с помощью параметра `client_writeback_allowed`,
|
Можно обойти и это ограничение с помощью параметра `client_writeback_allowed`,
|
||||||
|
|||||||
@@ -30,6 +30,18 @@
|
|||||||
будут использоваться обычные синхронные системные вызовы send/recv. Для OSD
|
будут использоваться обычные синхронные системные вызовы send/recv. Для OSD
|
||||||
это бессмысленно, так как OSD в любом случае нуждается в io_uring, но, в
|
это бессмысленно, так как OSD в любом случае нуждается в io_uring, но, в
|
||||||
принципе, это может применяться для клиентов со старыми версиями ядра.
|
принципе, это может применяться для клиентов со старыми версиями ядра.
|
||||||
|
- name: use_zerocopy_send
|
||||||
|
type: bool
|
||||||
|
default: false
|
||||||
|
info: |
|
||||||
|
If true, OSDs and clients will attempt to use TCP zero-copy send
|
||||||
|
(MSG_ZEROCOPY) for big buffers. It's recommended to raise net.ipv4.tcp_wmem
|
||||||
|
and net.core.wmem_max sysctls when using this mode.
|
||||||
|
info_ru: |
|
||||||
|
Если установлено в true, то OSD и клиенты будут стараться использовать
|
||||||
|
TCP-отправку без копирования (MSG_ZEROCOPY) для больших буферов данных.
|
||||||
|
Рекомендуется поднять значения sysctl net.ipv4.tcp_wmem и net.core.wmem_max
|
||||||
|
при использовании этого режима.
|
||||||
- name: use_rdma
|
- name: use_rdma
|
||||||
type: bool
|
type: bool
|
||||||
default: true
|
default: true
|
||||||
|
|||||||
@@ -51,13 +51,15 @@
|
|||||||
|
|
||||||
The following features are planned for the future:
|
The following features are planned for the future:
|
||||||
|
|
||||||
|
- File system
|
||||||
|
- Control plane optimisation
|
||||||
- Other administrative tools
|
- Other administrative tools
|
||||||
- Web GUI
|
- Web GUI
|
||||||
- OpenNebula plugin
|
- OpenNebula plugin
|
||||||
- iSCSI proxy
|
- iSCSI and NVMeoF gateways
|
||||||
- Multi-threaded client
|
- Multi-threaded client
|
||||||
- Faster failover
|
- Faster failover
|
||||||
|
- S3
|
||||||
- Tiered storage (SSD caching)
|
- Tiered storage (SSD caching)
|
||||||
- NVDIMM support
|
- NVDIMM support
|
||||||
- Compression (possibly)
|
- Compression (possibly)
|
||||||
- Read caching using system page cache (possibly)
|
|
||||||
|
|||||||
@@ -51,12 +51,15 @@
|
|||||||
|
|
||||||
## Планы развития
|
## Планы развития
|
||||||
|
|
||||||
|
- Файловая система
|
||||||
|
- Оптимизация слоя управления
|
||||||
- Другие инструменты администрирования
|
- Другие инструменты администрирования
|
||||||
- Web-интерфейс
|
- Web-интерфейс
|
||||||
- Плагин для OpenNebula
|
- Плагин для OpenNebula
|
||||||
- iSCSI-прокси
|
- iSCSI и NVMeoF прокси
|
||||||
- Многопоточный клиент
|
- Многопоточный клиент
|
||||||
- Более быстрое переключение при отказах
|
- Более быстрое переключение при отказах
|
||||||
|
- S3
|
||||||
- Поддержка SSD-кэширования (tiered storage)
|
- Поддержка SSD-кэширования (tiered storage)
|
||||||
- Поддержка NVDIMM
|
- Поддержка NVDIMM
|
||||||
- Возможно, сжатие
|
- Возможно, сжатие
|
||||||
|
|||||||
+1
-1
Submodule json11 updated: fd37016cf8...52a3af664f
@@ -3,5 +3,5 @@ SUBSYSTEM=="block", ENV{ID_PART_ENTRY_TYPE}=="e7009fac-a5a1-4d72-af72-53de130599
|
|||||||
IMPORT{program}="/usr/bin/vitastor-disk udev $devnode", \
|
IMPORT{program}="/usr/bin/vitastor-disk udev $devnode", \
|
||||||
SYMLINK+="vitastor/$env{VITASTOR_ALIAS}"
|
SYMLINK+="vitastor/$env{VITASTOR_ALIAS}"
|
||||||
|
|
||||||
ENV{VITASTOR_OSD_NUM}!="", ACTION=="add", RUN{program}+="/usr/bin/systemctl enable --now vitastor-osd@$env{VITASTOR_OSD_NUM}"
|
ENV{VITASTOR_OSD_NUM}!="", ACTION=="add", RUN{program}+="/usr/bin/systemctl enable --now --no-block vitastor-osd@$env{VITASTOR_OSD_NUM}"
|
||||||
ENV{VITASTOR_OSD_NUM}!="", ACTION=="remove", RUN{program}+="/usr/bin/systemctl disable --now vitastor-osd@$env{VITASTOR_OSD_NUM}"
|
ENV{VITASTOR_OSD_NUM}!="", ACTION=="remove", RUN{program}+="/usr/bin/systemctl disable --now --no-block vitastor-osd@$env{VITASTOR_OSD_NUM}"
|
||||||
|
|||||||
+69
-37
@@ -65,6 +65,7 @@ const etcd_tree = {
|
|||||||
// client and osd
|
// client and osd
|
||||||
tcp_header_buffer_size: 65536,
|
tcp_header_buffer_size: 65536,
|
||||||
use_sync_send_recv: false,
|
use_sync_send_recv: false,
|
||||||
|
use_zerocopy_send: false,
|
||||||
use_rdma: true,
|
use_rdma: true,
|
||||||
rdma_device: null, // for example, "rocep5s0f0"
|
rdma_device: null, // for example, "rocep5s0f0"
|
||||||
rdma_port_num: 1,
|
rdma_port_num: 1,
|
||||||
@@ -397,8 +398,8 @@ class Mon
|
|||||||
this.etcd_prefix = this.etcd_prefix.replace(/\/\/+/g, '/').replace(/^\/?(.*[^\/])\/?$/, '/$1');
|
this.etcd_prefix = this.etcd_prefix.replace(/\/\/+/g, '/').replace(/^\/?(.*[^\/])\/?$/, '/$1');
|
||||||
this.etcd_start_timeout = (config.etcd_start_timeout || 5) * 1000;
|
this.etcd_start_timeout = (config.etcd_start_timeout || 5) * 1000;
|
||||||
this.state = JSON.parse(JSON.stringify(this.constructor.etcd_tree));
|
this.state = JSON.parse(JSON.stringify(this.constructor.etcd_tree));
|
||||||
|
this.prev_stats = { osd_stats: {}, osd_diff: {} };
|
||||||
this.signals_set = false;
|
this.signals_set = false;
|
||||||
this.stat_time = Date.now();
|
|
||||||
this.ws = null;
|
this.ws = null;
|
||||||
this.ws_alive = false;
|
this.ws_alive = false;
|
||||||
this.ws_keepalive_timer = null;
|
this.ws_keepalive_timer = null;
|
||||||
@@ -552,9 +553,9 @@ class Mon
|
|||||||
const cur_addr = this.pick_next_etcd();
|
const cur_addr = this.pick_next_etcd();
|
||||||
const base = 'ws'+cur_addr.substr(4);
|
const base = 'ws'+cur_addr.substr(4);
|
||||||
let now = Date.now();
|
let now = Date.now();
|
||||||
if (tried[base] && now-tried[base] < timeout)
|
if (tried[base] && now-tried[base] < this.etcd_start_timeout)
|
||||||
{
|
{
|
||||||
await new Promise(ok => setTimeout(ok, timeout-(now-tried[base])));
|
await new Promise(ok => setTimeout(ok, this.etcd_start_timeout-(now-tried[base])));
|
||||||
now = Date.now();
|
now = Date.now();
|
||||||
}
|
}
|
||||||
tried[base] = now;
|
tried[base] = now;
|
||||||
@@ -1459,15 +1460,15 @@ class Mon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
derive_osd_stats(st, prev)
|
derive_osd_stats(st, prev, prev_diff)
|
||||||
{
|
{
|
||||||
const zero_stats = { op: { bps: 0n, iops: 0n, lat: 0n }, subop: { iops: 0n, lat: 0n }, recovery: { bps: 0n, iops: 0n } };
|
const zero_stats = { op: { bps: 0n, iops: 0n, lat: 0n }, subop: { iops: 0n, lat: 0n }, recovery: { bps: 0n, iops: 0n } };
|
||||||
const diff = { op_stats: {}, subop_stats: {}, recovery_stats: {} };
|
const diff = { op_stats: {}, subop_stats: {}, recovery_stats: {}, inode_stats: {} };
|
||||||
if (!st || !st.time || prev && (prev.time || this.stat_time/1000) >= st.time)
|
if (!st || !st.time || !prev || prev.time >= st.time)
|
||||||
{
|
{
|
||||||
return diff;
|
return prev_diff || diff;
|
||||||
}
|
}
|
||||||
const timediff = BigInt(st.time*1000 - (prev && prev.time*1000 || this.stat_time));
|
const timediff = BigInt(st.time*1000 - prev.time*1000);
|
||||||
for (const op in st.op_stats||{})
|
for (const op in st.op_stats||{})
|
||||||
{
|
{
|
||||||
const pr = prev && prev.op_stats && prev.op_stats[op];
|
const pr = prev && prev.op_stats && prev.op_stats[op];
|
||||||
@@ -1499,25 +1500,47 @@ class Mon
|
|||||||
if (n > 0)
|
if (n > 0)
|
||||||
diff.recovery_stats[op] = { ...c, bps: b*1000n/timediff, iops: n*1000n/timediff };
|
diff.recovery_stats[op] = { ...c, bps: b*1000n/timediff, iops: n*1000n/timediff };
|
||||||
}
|
}
|
||||||
|
for (const pool_id in st.inode_stats||{})
|
||||||
|
{
|
||||||
|
const pool_diff = diff.inode_stats[pool_id] = {};
|
||||||
|
for (const inode_num in st.inode_stats[pool_id])
|
||||||
|
{
|
||||||
|
const inode_diff = diff.inode_stats[pool_id][inode_num] = {};
|
||||||
|
for (const op of [ 'read', 'write', 'delete' ])
|
||||||
|
{
|
||||||
|
const c = st.inode_stats[pool_id][inode_num][op];
|
||||||
|
const pr = prev && prev.inode_stats && prev.inode_stats[pool_id] &&
|
||||||
|
prev.inode_stats[pool_id][inode_num] && prev.inode_stats[pool_id][inode_num][op];
|
||||||
|
const n = BigInt(c.count||0) - BigInt(pr && pr.count||0);
|
||||||
|
inode_diff[op] = {
|
||||||
|
bps: (BigInt(c.bytes||0) - BigInt(pr && pr.bytes||0))*1000n/timediff,
|
||||||
|
iops: n*1000n/timediff,
|
||||||
|
lat: (BigInt(c.usec||0) - BigInt(pr && pr.usec||0))/(n || 1n),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
sum_op_stats(timestamp, prev_stats)
|
sum_op_stats()
|
||||||
{
|
{
|
||||||
const sum_diff = { op_stats: {}, subop_stats: {}, recovery_stats: {} };
|
for (const osd in this.state.osd.stats)
|
||||||
if (!prev_stats || prev_stats.timestamp >= timestamp)
|
|
||||||
{
|
{
|
||||||
return sum_diff;
|
const cur = { ...this.state.osd.stats[osd], inode_stats: this.state.osd.inodestats[osd]||{} };
|
||||||
|
this.prev_stats.osd_diff[osd] = this.derive_osd_stats(
|
||||||
|
cur, this.prev_stats.osd_stats[osd], this.prev_stats.osd_diff[osd]
|
||||||
|
);
|
||||||
|
this.prev_stats.osd_stats[osd] = cur;
|
||||||
}
|
}
|
||||||
const tm = BigInt(timestamp - (prev_stats.timestamp || 0));
|
const sum_diff = { op_stats: {}, subop_stats: {}, recovery_stats: {} };
|
||||||
// Sum derived values instead of deriving summed
|
// Sum derived values instead of deriving summed
|
||||||
for (const osd in this.state.osd.stats)
|
for (const osd in this.state.osd.stats)
|
||||||
{
|
{
|
||||||
const derived = this.derive_osd_stats(this.state.osd.stats[osd],
|
const derived = this.prev_stats.osd_diff[osd];
|
||||||
this.prev_stats && this.prev_stats.osd_stats && this.prev_stats.osd_stats[osd]);
|
for (const type in sum_diff)
|
||||||
for (const type in derived)
|
|
||||||
{
|
{
|
||||||
for (const op in derived[type])
|
for (const op in derived[type]||{})
|
||||||
{
|
{
|
||||||
for (const k in derived[type][op])
|
for (const k in derived[type][op])
|
||||||
{
|
{
|
||||||
@@ -1574,14 +1597,14 @@ class Mon
|
|||||||
return { object_counts, object_bytes };
|
return { object_counts, object_bytes };
|
||||||
}
|
}
|
||||||
|
|
||||||
sum_inode_stats(prev_stats, timestamp, prev_timestamp)
|
sum_inode_stats()
|
||||||
{
|
{
|
||||||
const inode_stats = {};
|
const inode_stats = {};
|
||||||
const inode_stub = () => ({
|
const inode_stub = () => ({
|
||||||
raw_used: 0n,
|
raw_used: 0n,
|
||||||
read: { count: 0n, usec: 0n, bytes: 0n },
|
read: { count: 0n, usec: 0n, bytes: 0n, bps: 0n, iops: 0n, lat: 0n },
|
||||||
write: { count: 0n, usec: 0n, bytes: 0n },
|
write: { count: 0n, usec: 0n, bytes: 0n, bps: 0n, iops: 0n, lat: 0n },
|
||||||
delete: { count: 0n, usec: 0n, bytes: 0n },
|
delete: { count: 0n, usec: 0n, bytes: 0n, bps: 0n, iops: 0n, lat: 0n },
|
||||||
});
|
});
|
||||||
const seen_pools = {};
|
const seen_pools = {};
|
||||||
for (const pool_id in this.state.config.pools)
|
for (const pool_id in this.state.config.pools)
|
||||||
@@ -1633,11 +1656,25 @@ class Mon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (prev_stats && prev_timestamp >= timestamp)
|
for (const osd in this.prev_stats.osd_diff)
|
||||||
{
|
{
|
||||||
prev_stats = null;
|
for (const pool_id in this.prev_stats.osd_diff[osd].inode_stats)
|
||||||
|
{
|
||||||
|
for (const inode_num in this.prev_stats.osd_diff[osd].inode_stats[pool_id])
|
||||||
|
{
|
||||||
|
inode_stats[pool_id][inode_num] = inode_stats[pool_id][inode_num] || inode_stub();
|
||||||
|
for (const op of [ 'read', 'write', 'delete' ])
|
||||||
|
{
|
||||||
|
const op_diff = this.prev_stats.osd_diff[osd].inode_stats[pool_id][inode_num][op] || {};
|
||||||
|
const op_st = inode_stats[pool_id][inode_num][op];
|
||||||
|
op_st.bps += op_diff.bps;
|
||||||
|
op_st.iops += op_diff.iops;
|
||||||
|
op_st.lat += op_diff.lat;
|
||||||
|
op_st.n_osd = (op_st.n_osd || 0) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const tm = prev_stats ? BigInt(timestamp - prev_timestamp) : 0;
|
|
||||||
for (const pool_id in inode_stats)
|
for (const pool_id in inode_stats)
|
||||||
{
|
{
|
||||||
for (const inode_num in inode_stats[pool_id])
|
for (const inode_num in inode_stats[pool_id])
|
||||||
@@ -1646,11 +1683,12 @@ class Mon
|
|||||||
for (const op of [ 'read', 'write', 'delete' ])
|
for (const op of [ 'read', 'write', 'delete' ])
|
||||||
{
|
{
|
||||||
const op_st = inode_stats[pool_id][inode_num][op];
|
const op_st = inode_stats[pool_id][inode_num][op];
|
||||||
const prev_st = prev_stats && prev_stats[pool_id] && prev_stats[pool_id][inode_num] && prev_stats[pool_id][inode_num][op];
|
if (op_st.n_osd)
|
||||||
op_st.bps = prev_st ? (op_st.bytes - prev_st.bytes) * 1000n / tm : 0;
|
{
|
||||||
op_st.iops = prev_st ? (op_st.count - prev_st.count) * 1000n / tm : 0;
|
op_st.lat /= BigInt(op_st.n_osd);
|
||||||
op_st.lat = prev_st ? (op_st.usec - prev_st.usec) / ((op_st.count - prev_st.count) || 1n) : 0;
|
delete op_st.n_osd;
|
||||||
if (op_st.bps > 0 || op_st.iops > 0 || op_st.lat > 0)
|
}
|
||||||
|
if (op_st.bps > 0 || op_st.iops > 0)
|
||||||
nonzero = true;
|
nonzero = true;
|
||||||
}
|
}
|
||||||
if (!nonzero && (!this.state.config.inode[pool_id] || !this.state.config.inode[pool_id][inode_num]))
|
if (!nonzero && (!this.state.config.inode[pool_id] || !this.state.config.inode[pool_id][inode_num]))
|
||||||
@@ -1683,15 +1721,9 @@ class Mon
|
|||||||
async update_total_stats()
|
async update_total_stats()
|
||||||
{
|
{
|
||||||
const txn = [];
|
const txn = [];
|
||||||
const timestamp = Date.now();
|
|
||||||
const { object_counts, object_bytes } = this.sum_object_counts();
|
const { object_counts, object_bytes } = this.sum_object_counts();
|
||||||
let stats = this.sum_op_stats(timestamp, this.prev_stats);
|
let stats = this.sum_op_stats();
|
||||||
let { inode_stats, seen_pools } = this.sum_inode_stats(
|
let { inode_stats, seen_pools } = this.sum_inode_stats();
|
||||||
this.prev_stats ? this.prev_stats.inode_stats : null,
|
|
||||||
timestamp, this.prev_stats ? this.prev_stats.timestamp : null
|
|
||||||
);
|
|
||||||
this.prev_stats = { timestamp, inode_stats, osd_stats: { ...this.state.osd.stats } };
|
|
||||||
this.stat_time = Date.now();
|
|
||||||
stats.object_counts = object_counts;
|
stats.object_counts = object_counts;
|
||||||
stats.object_bytes = object_bytes;
|
stats.object_bytes = object_bytes;
|
||||||
stats = this.serialize_bigints(stats);
|
stats = this.serialize_bigints(stats);
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ resume_1:
|
|||||||
pool_avail *= (pool_cfg.pg_size - pool_cfg.parity_chunks);
|
pool_avail *= (pool_cfg.pg_size - pool_cfg.parity_chunks);
|
||||||
}
|
}
|
||||||
pool_stats[pool_cfg.id] = json11::Json::object {
|
pool_stats[pool_cfg.id] = json11::Json::object {
|
||||||
|
{ "id", (uint64_t)pool_cfg.id },
|
||||||
{ "name", pool_cfg.name },
|
{ "name", pool_cfg.name },
|
||||||
{ "pg_count", pool_cfg.pg_count },
|
{ "pg_count", pool_cfg.pg_count },
|
||||||
{ "scheme", pool_cfg.scheme == POOL_SCHEME_REPLICATED ? "replicated" : "ec" },
|
{ "scheme", pool_cfg.scheme == POOL_SCHEME_REPLICATED ? "replicated" : "ec" },
|
||||||
|
|||||||
+33
-10
@@ -42,6 +42,12 @@ void osd_messenger_t::init()
|
|||||||
handle_rdma_events();
|
handle_rdma_events();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifndef SO_ZEROCOPY
|
||||||
|
if (log_level > 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Zero-copy TCP send is not supported in this build, ignoring\n");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
keepalive_timer_id = tfd->set_timer(1000, true, [this](int)
|
keepalive_timer_id = tfd->set_timer(1000, true, [this](int)
|
||||||
{
|
{
|
||||||
@@ -173,6 +179,8 @@ void osd_messenger_t::parse_config(const json11::Json & config)
|
|||||||
this->receive_buffer_size = 65536;
|
this->receive_buffer_size = 65536;
|
||||||
this->use_sync_send_recv = config["use_sync_send_recv"].bool_value() ||
|
this->use_sync_send_recv = config["use_sync_send_recv"].bool_value() ||
|
||||||
config["use_sync_send_recv"].uint64_value();
|
config["use_sync_send_recv"].uint64_value();
|
||||||
|
this->use_zerocopy_send = config["use_zerocopy_send"].bool_value() ||
|
||||||
|
config["use_zerocopy_send"].uint64_value();
|
||||||
this->peer_connect_interval = config["peer_connect_interval"].uint64_value();
|
this->peer_connect_interval = config["peer_connect_interval"].uint64_value();
|
||||||
if (!this->peer_connect_interval)
|
if (!this->peer_connect_interval)
|
||||||
this->peer_connect_interval = 5;
|
this->peer_connect_interval = 5;
|
||||||
@@ -303,8 +311,7 @@ void osd_messenger_t::handle_connect_epoll(int peer_fd)
|
|||||||
on_connect_peer(peer_osd, -result);
|
on_connect_peer(peer_osd, -result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int one = 1;
|
set_socket_options(cl);
|
||||||
setsockopt(peer_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
|
|
||||||
cl->peer_state = PEER_CONNECTED;
|
cl->peer_state = PEER_CONNECTED;
|
||||||
tfd->set_fd_handler(peer_fd, false, [this](int peer_fd, int epoll_events)
|
tfd->set_fd_handler(peer_fd, false, [this](int peer_fd, int epoll_events)
|
||||||
{
|
{
|
||||||
@@ -314,6 +321,23 @@ void osd_messenger_t::handle_connect_epoll(int peer_fd)
|
|||||||
check_peer_config(cl);
|
check_peer_config(cl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void osd_messenger_t::set_socket_options(osd_client_t *cl)
|
||||||
|
{
|
||||||
|
int one = 1;
|
||||||
|
setsockopt(cl->peer_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
|
||||||
|
#ifdef SO_ZEROCOPY
|
||||||
|
if (!use_zerocopy_send)
|
||||||
|
cl->zerocopy_send = false;
|
||||||
|
else if (setsockopt(cl->peer_fd, SOL_SOCKET, SO_ZEROCOPY, &one, sizeof(one)) != 0)
|
||||||
|
{
|
||||||
|
if (log_level > 0)
|
||||||
|
fprintf(stderr, "[OSD %lu] Failed to enable zero-copy send for client %d: %s\n", this->osd_num, cl->peer_fd, strerror(errno));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cl->zerocopy_send = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void osd_messenger_t::handle_peer_epoll(int peer_fd, int epoll_events)
|
void osd_messenger_t::handle_peer_epoll(int peer_fd, int epoll_events)
|
||||||
{
|
{
|
||||||
// Mark client as ready (i.e. some data is available)
|
// Mark client as ready (i.e. some data is available)
|
||||||
@@ -515,14 +539,13 @@ void osd_messenger_t::accept_connections(int listen_fd)
|
|||||||
fprintf(stderr, "[OSD %lu] new client %d: connection from %s\n", this->osd_num, peer_fd,
|
fprintf(stderr, "[OSD %lu] new client %d: connection from %s\n", this->osd_num, peer_fd,
|
||||||
addr_to_string(addr).c_str());
|
addr_to_string(addr).c_str());
|
||||||
fcntl(peer_fd, F_SETFL, fcntl(peer_fd, F_GETFL, 0) | O_NONBLOCK);
|
fcntl(peer_fd, F_SETFL, fcntl(peer_fd, F_GETFL, 0) | O_NONBLOCK);
|
||||||
int one = 1;
|
auto cl = clients[peer_fd] = new osd_client_t();
|
||||||
setsockopt(peer_fd, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
|
cl->peer_addr = addr;
|
||||||
clients[peer_fd] = new osd_client_t();
|
cl->peer_port = ntohs(((sockaddr_in*)&addr)->sin_port);
|
||||||
clients[peer_fd]->peer_addr = addr;
|
cl->peer_fd = peer_fd;
|
||||||
clients[peer_fd]->peer_port = ntohs(((sockaddr_in*)&addr)->sin_port);
|
cl->peer_state = PEER_CONNECTED;
|
||||||
clients[peer_fd]->peer_fd = peer_fd;
|
cl->in_buf = malloc_or_die(receive_buffer_size);
|
||||||
clients[peer_fd]->peer_state = PEER_CONNECTED;
|
set_socket_options(cl);
|
||||||
clients[peer_fd]->in_buf = malloc_or_die(receive_buffer_size);
|
|
||||||
// Add FD to epoll
|
// Add FD to epoll
|
||||||
tfd->set_fd_handler(peer_fd, false, [this](int peer_fd, int epoll_events)
|
tfd->set_fd_handler(peer_fd, false, [this](int peer_fd, int epoll_events)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -45,6 +45,12 @@ struct msgr_rdma_connection_t;
|
|||||||
struct msgr_rdma_context_t;
|
struct msgr_rdma_context_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct msgr_zc_not_t
|
||||||
|
{
|
||||||
|
osd_op_t *op;
|
||||||
|
uint32_t nsend;
|
||||||
|
};
|
||||||
|
|
||||||
struct osd_client_t
|
struct osd_client_t
|
||||||
{
|
{
|
||||||
int refs = 0;
|
int refs = 0;
|
||||||
@@ -57,6 +63,7 @@ struct osd_client_t
|
|||||||
int ping_time_remaining = 0;
|
int ping_time_remaining = 0;
|
||||||
int idle_time_remaining = 0;
|
int idle_time_remaining = 0;
|
||||||
osd_num_t osd_num = 0;
|
osd_num_t osd_num = 0;
|
||||||
|
bool zerocopy_send = false;
|
||||||
|
|
||||||
void *in_buf = NULL;
|
void *in_buf = NULL;
|
||||||
|
|
||||||
@@ -87,6 +94,12 @@ struct osd_client_t
|
|||||||
int write_state = 0;
|
int write_state = 0;
|
||||||
std::vector<iovec> send_list, next_send_list;
|
std::vector<iovec> send_list, next_send_list;
|
||||||
std::vector<msgr_sendp_t> outbox, next_outbox;
|
std::vector<msgr_sendp_t> outbox, next_outbox;
|
||||||
|
std::vector<msgr_zc_not_t> zerocopy_sent;
|
||||||
|
uint64_t outbox_size = 0, next_outbox_size = 0;
|
||||||
|
uint32_t zerocopy_notification_idx = 0;
|
||||||
|
uint32_t zerocopy_notification_prev = 0;
|
||||||
|
uint8_t zerocopy_notification_buf[256];
|
||||||
|
struct msghdr zerocopy_notification_msg;
|
||||||
|
|
||||||
~osd_client_t();
|
~osd_client_t();
|
||||||
};
|
};
|
||||||
@@ -123,6 +136,7 @@ protected:
|
|||||||
int osd_ping_timeout = 0;
|
int osd_ping_timeout = 0;
|
||||||
int log_level = 0;
|
int log_level = 0;
|
||||||
bool use_sync_send_recv = false;
|
bool use_sync_send_recv = false;
|
||||||
|
bool use_zerocopy_send = false;
|
||||||
|
|
||||||
#ifdef WITH_RDMA
|
#ifdef WITH_RDMA
|
||||||
bool use_rdma = true;
|
bool use_rdma = true;
|
||||||
@@ -185,9 +199,11 @@ protected:
|
|||||||
void check_peer_config(osd_client_t *cl);
|
void check_peer_config(osd_client_t *cl);
|
||||||
void cancel_osd_ops(osd_client_t *cl);
|
void cancel_osd_ops(osd_client_t *cl);
|
||||||
void cancel_op(osd_op_t *op);
|
void cancel_op(osd_op_t *op);
|
||||||
|
void set_socket_options(osd_client_t *cl);
|
||||||
|
|
||||||
bool try_send(osd_client_t *cl);
|
bool try_send(osd_client_t *cl);
|
||||||
void handle_send(int result, osd_client_t *cl);
|
void handle_send(int result, osd_client_t *cl);
|
||||||
|
void handle_zerocopy_notification(osd_client_t *cl, int res);
|
||||||
|
|
||||||
bool handle_read(int result, osd_client_t *cl);
|
bool handle_read(int result, osd_client_t *cl);
|
||||||
bool handle_read_buffer(osd_client_t *cl, void *curbuf, int remain);
|
bool handle_read_buffer(osd_client_t *cl, void *curbuf, int remain);
|
||||||
|
|||||||
+133
-6
@@ -6,6 +6,12 @@
|
|||||||
|
|
||||||
#include "messenger.h"
|
#include "messenger.h"
|
||||||
|
|
||||||
|
#include <linux/errqueue.h>
|
||||||
|
|
||||||
|
#ifndef MSG_ZEROCOPY
|
||||||
|
#define MSG_ZEROCOPY 0
|
||||||
|
#endif
|
||||||
|
|
||||||
void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
||||||
{
|
{
|
||||||
assert(cur_op->peer_fd);
|
assert(cur_op->peer_fd);
|
||||||
@@ -36,6 +42,7 @@ void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
|||||||
}
|
}
|
||||||
auto & to_send_list = cl->write_msg.msg_iovlen ? cl->next_send_list : cl->send_list;
|
auto & to_send_list = cl->write_msg.msg_iovlen ? cl->next_send_list : cl->send_list;
|
||||||
auto & to_outbox = cl->write_msg.msg_iovlen ? cl->next_outbox : cl->outbox;
|
auto & to_outbox = cl->write_msg.msg_iovlen ? cl->next_outbox : cl->outbox;
|
||||||
|
auto & to_size = cl->write_msg.msg_iovlen ? cl->next_outbox_size : cl->outbox_size;
|
||||||
if (cur_op->op_type == OSD_OP_IN)
|
if (cur_op->op_type == OSD_OP_IN)
|
||||||
{
|
{
|
||||||
measure_exec(cur_op);
|
measure_exec(cur_op);
|
||||||
@@ -46,6 +53,7 @@ void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
|||||||
to_send_list.push_back((iovec){ .iov_base = cur_op->req.buf, .iov_len = OSD_PACKET_SIZE });
|
to_send_list.push_back((iovec){ .iov_base = cur_op->req.buf, .iov_len = OSD_PACKET_SIZE });
|
||||||
cl->sent_ops[cur_op->req.hdr.id] = cur_op;
|
cl->sent_ops[cur_op->req.hdr.id] = cur_op;
|
||||||
}
|
}
|
||||||
|
to_size += OSD_PACKET_SIZE;
|
||||||
to_outbox.push_back((msgr_sendp_t){ .op = cur_op, .flags = MSGR_SENDP_HDR });
|
to_outbox.push_back((msgr_sendp_t){ .op = cur_op, .flags = MSGR_SENDP_HDR });
|
||||||
// Bitmap
|
// Bitmap
|
||||||
if (cur_op->op_type == OSD_OP_IN &&
|
if (cur_op->op_type == OSD_OP_IN &&
|
||||||
@@ -57,6 +65,7 @@ void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
|||||||
.iov_len = cur_op->reply.sec_rw.attr_len,
|
.iov_len = cur_op->reply.sec_rw.attr_len,
|
||||||
});
|
});
|
||||||
to_outbox.push_back((msgr_sendp_t){ .op = cur_op, .flags = 0 });
|
to_outbox.push_back((msgr_sendp_t){ .op = cur_op, .flags = 0 });
|
||||||
|
to_size += cur_op->reply.sec_rw.attr_len;
|
||||||
}
|
}
|
||||||
else if (cur_op->op_type == OSD_OP_OUT &&
|
else if (cur_op->op_type == OSD_OP_OUT &&
|
||||||
(cur_op->req.hdr.opcode == OSD_OP_SEC_WRITE || cur_op->req.hdr.opcode == OSD_OP_SEC_WRITE_STABLE) &&
|
(cur_op->req.hdr.opcode == OSD_OP_SEC_WRITE || cur_op->req.hdr.opcode == OSD_OP_SEC_WRITE_STABLE) &&
|
||||||
@@ -67,6 +76,7 @@ void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
|||||||
.iov_len = cur_op->req.sec_rw.attr_len,
|
.iov_len = cur_op->req.sec_rw.attr_len,
|
||||||
});
|
});
|
||||||
to_outbox.push_back((msgr_sendp_t){ .op = cur_op, .flags = 0 });
|
to_outbox.push_back((msgr_sendp_t){ .op = cur_op, .flags = 0 });
|
||||||
|
to_size += cur_op->req.sec_rw.attr_len;
|
||||||
}
|
}
|
||||||
// Operation data
|
// Operation data
|
||||||
if ((cur_op->op_type == OSD_OP_IN
|
if ((cur_op->op_type == OSD_OP_IN
|
||||||
@@ -89,15 +99,22 @@ void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
|||||||
assert(cur_op->iov.buf[i].iov_base);
|
assert(cur_op->iov.buf[i].iov_base);
|
||||||
to_send_list.push_back(cur_op->iov.buf[i]);
|
to_send_list.push_back(cur_op->iov.buf[i]);
|
||||||
to_outbox.push_back((msgr_sendp_t){ .op = cur_op, .flags = 0 });
|
to_outbox.push_back((msgr_sendp_t){ .op = cur_op, .flags = 0 });
|
||||||
|
to_size += cur_op->iov.buf[i].iov_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (cur_op->req.hdr.opcode == OSD_OP_SEC_READ_BMP)
|
if (cur_op->req.hdr.opcode == OSD_OP_SEC_READ_BMP)
|
||||||
{
|
{
|
||||||
if (cur_op->op_type == OSD_OP_IN && cur_op->reply.hdr.retval > 0)
|
if (cur_op->op_type == OSD_OP_IN && cur_op->reply.hdr.retval > 0)
|
||||||
|
{
|
||||||
to_send_list.push_back((iovec){ .iov_base = cur_op->buf, .iov_len = (size_t)cur_op->reply.hdr.retval });
|
to_send_list.push_back((iovec){ .iov_base = cur_op->buf, .iov_len = (size_t)cur_op->reply.hdr.retval });
|
||||||
|
to_size += cur_op->reply.hdr.retval;
|
||||||
|
}
|
||||||
else if (cur_op->op_type == OSD_OP_OUT && cur_op->req.sec_read_bmp.len > 0)
|
else if (cur_op->op_type == OSD_OP_OUT && cur_op->req.sec_read_bmp.len > 0)
|
||||||
|
{
|
||||||
to_send_list.push_back((iovec){ .iov_base = cur_op->buf, .iov_len = (size_t)cur_op->req.sec_read_bmp.len });
|
to_send_list.push_back((iovec){ .iov_base = cur_op->buf, .iov_len = (size_t)cur_op->req.sec_read_bmp.len });
|
||||||
|
to_size += cur_op->req.sec_read_bmp.len;
|
||||||
|
}
|
||||||
to_outbox.push_back((msgr_sendp_t){ .op = cur_op, .flags = 0 });
|
to_outbox.push_back((msgr_sendp_t){ .op = cur_op, .flags = 0 });
|
||||||
}
|
}
|
||||||
if (cur_op->op_type == OSD_OP_IN)
|
if (cur_op->op_type == OSD_OP_IN)
|
||||||
@@ -119,9 +136,9 @@ void osd_messenger_t::outbox_push(osd_op_t *cur_op)
|
|||||||
try_send(cl);
|
try_send(cl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (cl->write_msg.msg_iovlen > 0 || !try_send(cl))
|
else
|
||||||
{
|
{
|
||||||
if (cl->write_state == 0)
|
if ((cl->write_msg.msg_iovlen > 0 || !try_send(cl)) && (cl->write_state == 0))
|
||||||
{
|
{
|
||||||
cl->write_state = CL_WRITE_READY;
|
cl->write_state = CL_WRITE_READY;
|
||||||
write_ready_clients.push_back(cur_op->peer_fd);
|
write_ready_clients.push_back(cur_op->peer_fd);
|
||||||
@@ -183,17 +200,19 @@ bool osd_messenger_t::try_send(osd_client_t *cl)
|
|||||||
}
|
}
|
||||||
cl->write_msg.msg_iov = cl->send_list.data();
|
cl->write_msg.msg_iov = cl->send_list.data();
|
||||||
cl->write_msg.msg_iovlen = cl->send_list.size() < IOV_MAX ? cl->send_list.size() : IOV_MAX;
|
cl->write_msg.msg_iovlen = cl->send_list.size() < IOV_MAX ? cl->send_list.size() : IOV_MAX;
|
||||||
|
cl->write_msg.msg_flags = (cl->zerocopy_send && (cl->outbox_size/cl->send_list.size()) >= 4096 ? MSG_ZEROCOPY : 0);
|
||||||
cl->refs++;
|
cl->refs++;
|
||||||
ring_data_t* data = ((ring_data_t*)sqe->user_data);
|
ring_data_t* data = ((ring_data_t*)sqe->user_data);
|
||||||
data->callback = [this, cl](ring_data_t *data) { handle_send(data->res, cl); };
|
data->callback = [this, cl](ring_data_t *data) { handle_send(data->res, cl); };
|
||||||
my_uring_prep_sendmsg(sqe, peer_fd, &cl->write_msg, 0);
|
my_uring_prep_sendmsg(sqe, peer_fd, &cl->write_msg, cl->write_msg.msg_flags);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cl->write_msg.msg_iov = cl->send_list.data();
|
cl->write_msg.msg_iov = cl->send_list.data();
|
||||||
cl->write_msg.msg_iovlen = cl->send_list.size() < IOV_MAX ? cl->send_list.size() : IOV_MAX;
|
cl->write_msg.msg_iovlen = cl->send_list.size() < IOV_MAX ? cl->send_list.size() : IOV_MAX;
|
||||||
|
cl->write_msg.msg_flags = (cl->zerocopy_send && (cl->outbox_size/cl->send_list.size()) >= 4096 ? MSG_ZEROCOPY : 0);
|
||||||
cl->refs++;
|
cl->refs++;
|
||||||
int result = sendmsg(peer_fd, &cl->write_msg, MSG_NOSIGNAL);
|
int result = sendmsg(peer_fd, &cl->write_msg, MSG_NOSIGNAL | cl->write_msg.msg_flags);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
{
|
{
|
||||||
result = -errno;
|
result = -errno;
|
||||||
@@ -203,6 +222,62 @@ bool osd_messenger_t::try_send(osd_client_t *cl)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void osd_messenger_t::handle_zerocopy_notification(osd_client_t *cl, int res)
|
||||||
|
{
|
||||||
|
cl->refs--;
|
||||||
|
if (cl->peer_state == PEER_STOPPED)
|
||||||
|
{
|
||||||
|
if (cl->refs <= 0)
|
||||||
|
{
|
||||||
|
delete cl;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (cl->zerocopy_notification_msg.msg_flags & MSG_CTRUNC)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "zero-copy send notification truncated on client socket %d\n", cl->peer_fd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (struct cmsghdr *cm = CMSG_FIRSTHDR(&cl->zerocopy_notification_msg); cm; cm = CMSG_NXTHDR(&cl->zerocopy_notification_msg, cm))
|
||||||
|
{
|
||||||
|
if (cm->cmsg_level == SOL_IP && cm->cmsg_type == IP_RECVERR)
|
||||||
|
{
|
||||||
|
struct sock_extended_err *serr = (struct sock_extended_err*)CMSG_DATA(cm);
|
||||||
|
if (serr->ee_errno == 0 && serr->ee_origin == SO_EE_ORIGIN_ZEROCOPY)
|
||||||
|
{
|
||||||
|
// completed sends numbered serr->ee_info .. serr->ee_data
|
||||||
|
int start = 0;
|
||||||
|
while (start < cl->zerocopy_sent.size() && cl->zerocopy_sent[start].nsend < serr->ee_info)
|
||||||
|
start++;
|
||||||
|
int end = start;
|
||||||
|
if (serr->ee_data < serr->ee_info)
|
||||||
|
{
|
||||||
|
// counter has wrapped around
|
||||||
|
while (end < cl->zerocopy_sent.size() && cl->zerocopy_sent[end].nsend >= cl->zerocopy_sent[start].nsend)
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
while (end < cl->zerocopy_sent.size() && cl->zerocopy_sent[end].nsend <= serr->ee_data)
|
||||||
|
end++;
|
||||||
|
if (end > start)
|
||||||
|
{
|
||||||
|
for (int i = start; i < end; i++)
|
||||||
|
{
|
||||||
|
delete cl->zerocopy_sent[i].op;
|
||||||
|
}
|
||||||
|
cl->zerocopy_sent.erase(
|
||||||
|
cl->zerocopy_sent.begin() + start,
|
||||||
|
cl->zerocopy_sent.begin() + end
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void osd_messenger_t::send_replies()
|
void osd_messenger_t::send_replies()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < write_ready_clients.size(); i++)
|
for (int i = 0; i < write_ready_clients.size(); i++)
|
||||||
@@ -230,16 +305,19 @@ void osd_messenger_t::handle_send(int result, osd_client_t *cl)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (result < 0 && result != -EAGAIN && result != -EINTR)
|
if (result < 0 && result != -EAGAIN && result != -EINTR && result != -ENOBUFS)
|
||||||
{
|
{
|
||||||
// this is a client socket, so don't panic. just disconnect it
|
// this is a client socket, so don't panic. just disconnect it
|
||||||
fprintf(stderr, "Client %d socket write error: %d (%s). Disconnecting client\n", cl->peer_fd, -result, strerror(-result));
|
fprintf(stderr, "Client %d socket write error: %d (%s). Disconnecting client\n", cl->peer_fd, -result, strerror(-result));
|
||||||
stop_client(cl->peer_fd);
|
stop_client(cl->peer_fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
bool used_zerocopy = false;
|
||||||
if (result >= 0)
|
if (result >= 0)
|
||||||
{
|
{
|
||||||
|
used_zerocopy = (cl->write_msg.msg_flags & MSG_ZEROCOPY) ? true : false;
|
||||||
int done = 0;
|
int done = 0;
|
||||||
|
int bytes_written = result;
|
||||||
while (result > 0 && done < cl->send_list.size())
|
while (result > 0 && done < cl->send_list.size())
|
||||||
{
|
{
|
||||||
iovec & iov = cl->send_list[done];
|
iovec & iov = cl->send_list[done];
|
||||||
@@ -248,7 +326,19 @@ void osd_messenger_t::handle_send(int result, osd_client_t *cl)
|
|||||||
if (cl->outbox[done].flags & MSGR_SENDP_FREE)
|
if (cl->outbox[done].flags & MSGR_SENDP_FREE)
|
||||||
{
|
{
|
||||||
// Reply fully sent
|
// Reply fully sent
|
||||||
delete cl->outbox[done].op;
|
if (!used_zerocopy)
|
||||||
|
{
|
||||||
|
delete cl->outbox[done].op;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// With zero-copy send the difference is that we must keep the buffer (i.e. the operation)
|
||||||
|
// allocated until we get send notification from MSG_ERRQUEUE
|
||||||
|
cl->zerocopy_sent.push_back((msgr_zc_not_t){
|
||||||
|
.op = cl->outbox[done].op,
|
||||||
|
.nsend = cl->zerocopy_notification_idx,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result -= iov.iov_len;
|
result -= iov.iov_len;
|
||||||
done++;
|
done++;
|
||||||
@@ -260,6 +350,11 @@ void osd_messenger_t::handle_send(int result, osd_client_t *cl)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (used_zerocopy)
|
||||||
|
{
|
||||||
|
cl->zerocopy_notification_idx++;
|
||||||
|
}
|
||||||
|
cl->outbox_size -= bytes_written;
|
||||||
if (done > 0)
|
if (done > 0)
|
||||||
{
|
{
|
||||||
cl->send_list.erase(cl->send_list.begin(), cl->send_list.begin()+done);
|
cl->send_list.erase(cl->send_list.begin(), cl->send_list.begin()+done);
|
||||||
@@ -269,8 +364,10 @@ void osd_messenger_t::handle_send(int result, osd_client_t *cl)
|
|||||||
{
|
{
|
||||||
cl->send_list.insert(cl->send_list.end(), cl->next_send_list.begin(), cl->next_send_list.end());
|
cl->send_list.insert(cl->send_list.end(), cl->next_send_list.begin(), cl->next_send_list.end());
|
||||||
cl->outbox.insert(cl->outbox.end(), cl->next_outbox.begin(), cl->next_outbox.end());
|
cl->outbox.insert(cl->outbox.end(), cl->next_outbox.begin(), cl->next_outbox.end());
|
||||||
|
cl->outbox_size += cl->next_outbox_size;
|
||||||
cl->next_send_list.clear();
|
cl->next_send_list.clear();
|
||||||
cl->next_outbox.clear();
|
cl->next_outbox.clear();
|
||||||
|
cl->next_outbox_size = 0;
|
||||||
}
|
}
|
||||||
cl->write_state = cl->outbox.size() > 0 ? CL_WRITE_READY : 0;
|
cl->write_state = cl->outbox.size() > 0 ? CL_WRITE_READY : 0;
|
||||||
#ifdef WITH_RDMA
|
#ifdef WITH_RDMA
|
||||||
@@ -293,4 +390,34 @@ void osd_messenger_t::handle_send(int result, osd_client_t *cl)
|
|||||||
{
|
{
|
||||||
write_ready_clients.push_back(cl->peer_fd);
|
write_ready_clients.push_back(cl->peer_fd);
|
||||||
}
|
}
|
||||||
|
if (used_zerocopy && (cl->zerocopy_notification_idx-cl->zerocopy_notification_prev) >= 16 &&
|
||||||
|
cl->zerocopy_sent.size() > 0)
|
||||||
|
{
|
||||||
|
cl->zerocopy_notification_prev = cl->zerocopy_notification_idx;
|
||||||
|
cl->zerocopy_notification_msg = {
|
||||||
|
.msg_control = cl->zerocopy_notification_buf,
|
||||||
|
.msg_controllen = sizeof(cl->zerocopy_notification_buf),
|
||||||
|
};
|
||||||
|
cl->refs++;
|
||||||
|
io_uring_sqe* sqe = NULL;
|
||||||
|
if (ringloop && !use_sync_send_recv)
|
||||||
|
{
|
||||||
|
sqe = ringloop->get_sqe();
|
||||||
|
}
|
||||||
|
if (!sqe)
|
||||||
|
{
|
||||||
|
int res = recvmsg(cl->peer_fd, &cl->zerocopy_notification_msg, MSG_ERRQUEUE|MSG_DONTWAIT);
|
||||||
|
if (res < 0)
|
||||||
|
{
|
||||||
|
res = -errno;
|
||||||
|
}
|
||||||
|
handle_zerocopy_notification(cl, res);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ring_data_t* data = ((ring_data_t*)sqe->user_data);
|
||||||
|
data->callback = [this, cl](ring_data_t *data) { handle_zerocopy_notification(cl, data->res); };
|
||||||
|
my_uring_prep_recvmsg(sqe, cl->peer_fd, &cl->zerocopy_notification_msg, MSG_ERRQUEUE);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-3
@@ -239,8 +239,9 @@ static void* get_jerasure_decoding_matrix(osd_rmw_stripe_t *stripes, int pg_size
|
|||||||
{
|
{
|
||||||
int edd = 0;
|
int edd = 0;
|
||||||
int erased[pg_size];
|
int erased[pg_size];
|
||||||
|
// we should distinguish stripes which are not at all and missing stripes
|
||||||
for (int i = 0; i < pg_size; i++)
|
for (int i = 0; i < pg_size; i++)
|
||||||
erased[i] = (stripes[i].read_end == 0 || stripes[i].missing ? 1 : 0);
|
erased[i] = (stripes[i].read_end == 0 ? 2 : (stripes[i].missing ? 1 : 0));
|
||||||
for (int i = 0; i < pg_minsize; i++)
|
for (int i = 0; i < pg_minsize; i++)
|
||||||
if (stripes[i].read_end != 0 && stripes[i].missing)
|
if (stripes[i].read_end != 0 && stripes[i].missing)
|
||||||
edd++;
|
edd++;
|
||||||
@@ -253,7 +254,7 @@ static void* get_jerasure_decoding_matrix(osd_rmw_stripe_t *stripes, int pg_size
|
|||||||
#ifdef WITH_ISAL
|
#ifdef WITH_ISAL
|
||||||
int smrow = 0;
|
int smrow = 0;
|
||||||
uint8_t *submatrix = (uint8_t*)malloc_or_die(pg_minsize*pg_minsize*2);
|
uint8_t *submatrix = (uint8_t*)malloc_or_die(pg_minsize*pg_minsize*2);
|
||||||
for (int i = 0; i < pg_size; i++)
|
for (int i = 0; i < pg_size && smrow < pg_minsize; i++)
|
||||||
{
|
{
|
||||||
if (!erased[i])
|
if (!erased[i])
|
||||||
{
|
{
|
||||||
@@ -279,7 +280,7 @@ static void* get_jerasure_decoding_matrix(osd_rmw_stripe_t *stripes, int pg_size
|
|||||||
smrow = 0;
|
smrow = 0;
|
||||||
for (int i = 0; i < pg_minsize; i++)
|
for (int i = 0; i < pg_minsize; i++)
|
||||||
{
|
{
|
||||||
if (erased[i])
|
if (erased[i] == 1)
|
||||||
{
|
{
|
||||||
memcpy(submatrix + pg_minsize*smrow, submatrix + (pg_minsize+i)*pg_minsize, pg_minsize);
|
memcpy(submatrix + pg_minsize*smrow, submatrix + (pg_minsize+i)*pg_minsize, pg_minsize);
|
||||||
smrow++;
|
smrow++;
|
||||||
|
|||||||
+67
-1
@@ -29,6 +29,7 @@ void test15(bool second);
|
|||||||
void test16();
|
void test16();
|
||||||
void test_recover_22_d2();
|
void test_recover_22_d2();
|
||||||
void test_ec43_error_bruteforce();
|
void test_ec43_error_bruteforce();
|
||||||
|
void test_recover_53_d5();
|
||||||
|
|
||||||
int main(int narg, char *args[])
|
int main(int narg, char *args[])
|
||||||
{
|
{
|
||||||
@@ -67,6 +68,8 @@ int main(int narg, char *args[])
|
|||||||
test_recover_22_d2();
|
test_recover_22_d2();
|
||||||
// Error bruteforce
|
// Error bruteforce
|
||||||
test_ec43_error_bruteforce();
|
test_ec43_error_bruteforce();
|
||||||
|
// Test 19
|
||||||
|
test_recover_53_d5();
|
||||||
// End
|
// End
|
||||||
printf("all ok\n");
|
printf("all ok\n");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1112,7 +1115,7 @@ void test_recover_22_d2()
|
|||||||
|
|
||||||
/***
|
/***
|
||||||
|
|
||||||
EC 4+2 error location bruteforce
|
18. EC 4+2 error location bruteforce
|
||||||
|
|
||||||
***/
|
***/
|
||||||
|
|
||||||
@@ -1178,3 +1181,66 @@ void test_ec43_error_bruteforce()
|
|||||||
free(write_buf);
|
free(write_buf);
|
||||||
use_ec(7, 4, false);
|
use_ec(7, 4, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
|
||||||
|
19. EC 5+3 recover 5th data block but not 4th
|
||||||
|
|
||||||
|
***/
|
||||||
|
|
||||||
|
void test_recover_53_d5()
|
||||||
|
{
|
||||||
|
const int bmp = 128*1024 / 4096 / 8;
|
||||||
|
use_ec(8, 5, true);
|
||||||
|
osd_num_t osd_set[8] = { 1, 2, 3, 0, 0, 6, 7, 8 };
|
||||||
|
osd_rmw_stripe_t stripes[8] = {};
|
||||||
|
unsigned bitmaps[8] = { 0 };
|
||||||
|
// Read 512+128K
|
||||||
|
split_stripes(5, 128*1024, 512*1024, 128*1024, stripes);
|
||||||
|
assert(stripes[0].req_start == 0 && stripes[0].req_end == 0);
|
||||||
|
assert(stripes[1].req_start == 0 && stripes[1].req_end == 0);
|
||||||
|
assert(stripes[2].req_start == 0 && stripes[2].req_end == 0);
|
||||||
|
assert(stripes[3].req_start == 0 && stripes[3].req_end == 0);
|
||||||
|
assert(stripes[4].req_start == 0 && stripes[4].req_end == 128*1024);
|
||||||
|
uint8_t *data_buf = (uint8_t*)malloc_or_die(128*1024*8);
|
||||||
|
for (int i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
stripes[i].read_start = stripes[i].req_start;
|
||||||
|
stripes[i].read_end = stripes[i].req_end;
|
||||||
|
stripes[i].read_buf = data_buf + i*128*1024;
|
||||||
|
stripes[i].bmp_buf = bitmaps + i;
|
||||||
|
}
|
||||||
|
// Read using parity
|
||||||
|
assert(extend_missing_stripes(stripes, osd_set, 5, 8) == 0);
|
||||||
|
assert(stripes[0].read_start == 0 && stripes[0].read_end == 128*1024);
|
||||||
|
assert(stripes[1].read_start == 0 && stripes[1].read_end == 128*1024);
|
||||||
|
assert(stripes[2].read_start == 0 && stripes[2].read_end == 128*1024);
|
||||||
|
assert(stripes[3].read_start == 0 && stripes[3].read_end == 0);
|
||||||
|
assert(stripes[4].read_start == 0 && stripes[4].read_end == 128*1024);
|
||||||
|
assert(stripes[5].read_start == 0 && stripes[5].read_end == 128*1024);
|
||||||
|
assert(stripes[6].read_start == 0 && stripes[6].read_end == 128*1024);
|
||||||
|
assert(stripes[7].read_start == 0 && stripes[7].read_end == 0);
|
||||||
|
bitmaps[0] = 0xffffffff;
|
||||||
|
bitmaps[1] = 0xffffffff;
|
||||||
|
bitmaps[2] = 0xffffffff;
|
||||||
|
bitmaps[3] = 0;
|
||||||
|
bitmaps[4] = 0;
|
||||||
|
bitmaps[5] = 0xffffffff;
|
||||||
|
bitmaps[6] = 0x64646464;
|
||||||
|
bitmaps[7] = 0;
|
||||||
|
set_pattern(stripes[0].read_buf, 128*1024, 0x70a549add9a2280a);
|
||||||
|
set_pattern(stripes[1].read_buf, 128*1024, 0xa70a549add9a2280);
|
||||||
|
set_pattern(stripes[2].read_buf, 128*1024, 0x0a70a549add9a228);
|
||||||
|
set_pattern(stripes[3].read_buf, 128*1024, 0); // 0x80a70a549add9a22
|
||||||
|
set_pattern(stripes[4].read_buf, 128*1024, 0); // 0x280a70a549add9a2
|
||||||
|
set_pattern(stripes[5].read_buf, 128*1024, 0x7572c28f7a91eb22); // xor
|
||||||
|
set_pattern(stripes[6].read_buf, 128*1024, 0xb4542b32a560fe26); // 2nd EC chunk
|
||||||
|
set_pattern(stripes[7].read_buf, 128*1024, 0);
|
||||||
|
// Reconstruct
|
||||||
|
reconstruct_stripes_ec(stripes, 8, 5, bmp);
|
||||||
|
check_pattern(stripes[4].read_buf, 128*1024, 0x280a70a549add9a2);
|
||||||
|
assert(bitmaps[4] == 0xFFFFFFFF);
|
||||||
|
free(data_buf);
|
||||||
|
// Done
|
||||||
|
use_ec(8, 5, false);
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ start_osd_on()
|
|||||||
{
|
{
|
||||||
local i=$1
|
local i=$1
|
||||||
local dev=$2
|
local dev=$2
|
||||||
build/src/vitastor-osd --osd_num $i --bind_address 127.0.0.1 $NO_SAME $OSD_ARGS --etcd_address $ETCD_URL \
|
build/src/vitastor-osd --osd_num $i --bind_address $ETCD_IP $NO_SAME $OSD_ARGS --etcd_address $ETCD_URL \
|
||||||
$(build/src/vitastor-disk simple-offsets --format options $OFFSET_ARGS $dev $OFFSET_ARGS 2>/dev/null) \
|
$(build/src/vitastor-disk simple-offsets --format options $OFFSET_ARGS $dev $OFFSET_ARGS 2>/dev/null) \
|
||||||
>>./testdata/osd$i.log 2>&1 &
|
>>./testdata/osd$i.log 2>&1 &
|
||||||
eval OSD${i}_PID=$!
|
eval OSD${i}_PID=$!
|
||||||
|
|||||||
Reference in New Issue
Block a user