Browse code

Relabel BTRFS Content on container Creation

This change will allow us to run SELinux in a container with
BTRFS back end. We continue to work on fixing the kernel/BTRFS
but this change will allow SELinux Security separation on BTRFS.

It basically relabels the content on container creation.

Just relabling -init directory in BTRFS use case. Everything looks like it
works. I don't believe tar/achive stores the SELinux labels, so we are good
as far as docker commit.

Tested Speed on startup with BTRFS on top of loopback directory. BTRFS
not on loopback should get even better perfomance on startup time. The
more inodes inside of the container image will increase the relabel time.

This patch will give people who care more about security the option of
runnin BTRFS with SELinux. Those who don't want to take the slow down
can disable SELinux either in individual containers or for all containers
by continuing to disable SELinux in the daemon.

Without relabel:

> time docker run --security-opt label:disable fedora echo test
test

real 0m0.918s
user 0m0.009s
sys 0m0.026s

With Relabel

test

real 0m1.942s
user 0m0.007s
sys 0m0.030s

Signed-off-by: Dan Walsh <dwalsh@redhat.com>

Signed-off-by: Dan Walsh <dwalsh@redhat.com>

Dan Walsh authored on 2015/10/28 22:19:51
Showing 19 changed files
... ...
@@ -87,6 +87,12 @@ func (daemon *Daemon) create(params *ContainerCreateConfig) (retC *Container, re
87 87
 	if err := daemon.Register(container); err != nil {
88 88
 		return nil, err
89 89
 	}
90
+	container.Lock()
91
+	if err := parseSecurityOpt(container, params.HostConfig); err != nil {
92
+		container.Unlock()
93
+		return nil, err
94
+	}
95
+	container.Unlock()
90 96
 	if err := daemon.createRootfs(container); err != nil {
91 97
 		return nil, err
92 98
 	}
... ...
@@ -991,7 +991,8 @@ func (daemon *Daemon) createRootfs(container *Container) error {
991 991
 		return err
992 992
 	}
993 993
 	initID := fmt.Sprintf("%s-init", container.ID)
994
-	if err := daemon.driver.Create(initID, container.ImageID); err != nil {
994
+
995
+	if err := daemon.driver.Create(initID, container.ImageID, container.getMountLabel()); err != nil {
995 996
 		return err
996 997
 	}
997 998
 	initPath, err := daemon.driver.Get(initID, "")
... ...
@@ -1012,7 +1013,7 @@ func (daemon *Daemon) createRootfs(container *Container) error {
1012 1012
 		return err
1013 1013
 	}
1014 1014
 
1015
-	if err := daemon.driver.Create(container.ID, initID); err != nil {
1015
+	if err := daemon.driver.Create(container.ID, initID, ""); err != nil {
1016 1016
 		return err
1017 1017
 	}
1018 1018
 	return nil
... ...
@@ -1187,12 +1188,6 @@ func tempDir(rootDir string, rootUID, rootGID int) (string, error) {
1187 1187
 }
1188 1188
 
1189 1189
 func (daemon *Daemon) setHostConfig(container *Container, hostConfig *runconfig.HostConfig) error {
1190
-	container.Lock()
1191
-	if err := parseSecurityOpt(container, hostConfig); err != nil {
1192
-		container.Unlock()
1193
-		return err
1194
-	}
1195
-	container.Unlock()
1196 1190
 
1197 1191
 	// Do not lock while creating volumes since this could be calling out to external plugins
1198 1192
 	// Don't want to block other actions, like `docker ps` because we're waiting on an external plugin
... ...
@@ -259,8 +259,8 @@ func checkSystem() error {
259 259
 func configureKernelSecuritySupport(config *Config, driverName string) error {
260 260
 	if config.EnableSelinuxSupport {
261 261
 		if selinuxEnabled() {
262
-			// As Docker on either btrfs or overlayFS and SELinux are incompatible at present, error on both being enabled
263
-			if driverName == "btrfs" || driverName == "overlay" {
262
+			// As Docker on overlayFS and SELinux are incompatible at present, error on overlayfs being enabled
263
+			if driverName == "overlay" {
264 264
 				return fmt.Errorf("SELinux is not supported with the %s graph driver", driverName)
265 265
 			}
266 266
 			logrus.Debug("SELinux enabled successfully")
... ...
@@ -201,7 +201,7 @@ func (a *Driver) Exists(id string) bool {
201 201
 
202 202
 // Create three folders for each id
203 203
 // mnt, layers, and diff
204
-func (a *Driver) Create(id, parent string) error {
204
+func (a *Driver) Create(id, parent, mountLabel string) error {
205 205
 	if err := a.createDirsFor(id); err != nil {
206 206
 		return err
207 207
 	}
... ...
@@ -99,7 +99,7 @@ func TestCreateNewDir(t *testing.T) {
99 99
 	d := newDriver(t)
100 100
 	defer os.RemoveAll(tmp)
101 101
 
102
-	if err := d.Create("1", ""); err != nil {
102
+	if err := d.Create("1", "", ""); err != nil {
103 103
 		t.Fatal(err)
104 104
 	}
105 105
 }
... ...
@@ -108,7 +108,7 @@ func TestCreateNewDirStructure(t *testing.T) {
108 108
 	d := newDriver(t)
109 109
 	defer os.RemoveAll(tmp)
110 110
 
111
-	if err := d.Create("1", ""); err != nil {
111
+	if err := d.Create("1", "", ""); err != nil {
112 112
 		t.Fatal(err)
113 113
 	}
114 114
 
... ...
@@ -129,7 +129,7 @@ func TestRemoveImage(t *testing.T) {
129 129
 	d := newDriver(t)
130 130
 	defer os.RemoveAll(tmp)
131 131
 
132
-	if err := d.Create("1", ""); err != nil {
132
+	if err := d.Create("1", "", ""); err != nil {
133 133
 		t.Fatal(err)
134 134
 	}
135 135
 
... ...
@@ -154,7 +154,7 @@ func TestGetWithoutParent(t *testing.T) {
154 154
 	d := newDriver(t)
155 155
 	defer os.RemoveAll(tmp)
156 156
 
157
-	if err := d.Create("1", ""); err != nil {
157
+	if err := d.Create("1", "", ""); err != nil {
158 158
 		t.Fatal(err)
159 159
 	}
160 160
 
... ...
@@ -181,7 +181,7 @@ func TestCleanupWithDir(t *testing.T) {
181 181
 	d := newDriver(t)
182 182
 	defer os.RemoveAll(tmp)
183 183
 
184
-	if err := d.Create("1", ""); err != nil {
184
+	if err := d.Create("1", "", ""); err != nil {
185 185
 		t.Fatal(err)
186 186
 	}
187 187
 
... ...
@@ -194,7 +194,7 @@ func TestMountedFalseResponse(t *testing.T) {
194 194
 	d := newDriver(t)
195 195
 	defer os.RemoveAll(tmp)
196 196
 
197
-	if err := d.Create("1", ""); err != nil {
197
+	if err := d.Create("1", "", ""); err != nil {
198 198
 		t.Fatal(err)
199 199
 	}
200 200
 
... ...
@@ -213,10 +213,10 @@ func TestMountedTrueReponse(t *testing.T) {
213 213
 	defer os.RemoveAll(tmp)
214 214
 	defer d.Cleanup()
215 215
 
216
-	if err := d.Create("1", ""); err != nil {
216
+	if err := d.Create("1", "", ""); err != nil {
217 217
 		t.Fatal(err)
218 218
 	}
219
-	if err := d.Create("2", "1"); err != nil {
219
+	if err := d.Create("2", "1", ""); err != nil {
220 220
 		t.Fatal(err)
221 221
 	}
222 222
 
... ...
@@ -239,10 +239,10 @@ func TestMountWithParent(t *testing.T) {
239 239
 	d := newDriver(t)
240 240
 	defer os.RemoveAll(tmp)
241 241
 
242
-	if err := d.Create("1", ""); err != nil {
242
+	if err := d.Create("1", "", ""); err != nil {
243 243
 		t.Fatal(err)
244 244
 	}
245
-	if err := d.Create("2", "1"); err != nil {
245
+	if err := d.Create("2", "1", ""); err != nil {
246 246
 		t.Fatal(err)
247 247
 	}
248 248
 
... ...
@@ -270,10 +270,10 @@ func TestRemoveMountedDir(t *testing.T) {
270 270
 	d := newDriver(t)
271 271
 	defer os.RemoveAll(tmp)
272 272
 
273
-	if err := d.Create("1", ""); err != nil {
273
+	if err := d.Create("1", "", ""); err != nil {
274 274
 		t.Fatal(err)
275 275
 	}
276
-	if err := d.Create("2", "1"); err != nil {
276
+	if err := d.Create("2", "1", ""); err != nil {
277 277
 		t.Fatal(err)
278 278
 	}
279 279
 
... ...
@@ -309,7 +309,7 @@ func TestCreateWithInvalidParent(t *testing.T) {
309 309
 	d := newDriver(t)
310 310
 	defer os.RemoveAll(tmp)
311 311
 
312
-	if err := d.Create("1", "docker"); err == nil {
312
+	if err := d.Create("1", "docker", ""); err == nil {
313 313
 		t.Fatalf("Error should not be nil with parent does not exist")
314 314
 	}
315 315
 }
... ...
@@ -318,7 +318,7 @@ func TestGetDiff(t *testing.T) {
318 318
 	d := newDriver(t)
319 319
 	defer os.RemoveAll(tmp)
320 320
 
321
-	if err := d.Create("1", ""); err != nil {
321
+	if err := d.Create("1", "", ""); err != nil {
322 322
 		t.Fatal(err)
323 323
 	}
324 324
 
... ...
@@ -352,10 +352,10 @@ func TestChanges(t *testing.T) {
352 352
 	d := newDriver(t)
353 353
 	defer os.RemoveAll(tmp)
354 354
 
355
-	if err := d.Create("1", ""); err != nil {
355
+	if err := d.Create("1", "", ""); err != nil {
356 356
 		t.Fatal(err)
357 357
 	}
358
-	if err := d.Create("2", "1"); err != nil {
358
+	if err := d.Create("2", "1", ""); err != nil {
359 359
 		t.Fatal(err)
360 360
 	}
361 361
 
... ...
@@ -401,7 +401,7 @@ func TestChanges(t *testing.T) {
401 401
 		t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
402 402
 	}
403 403
 
404
-	if err := d.Create("3", "2"); err != nil {
404
+	if err := d.Create("3", "2", ""); err != nil {
405 405
 		t.Fatal(err)
406 406
 	}
407 407
 	mntPoint, err = d.Get("3", "")
... ...
@@ -446,7 +446,7 @@ func TestDiffSize(t *testing.T) {
446 446
 	d := newDriver(t)
447 447
 	defer os.RemoveAll(tmp)
448 448
 
449
-	if err := d.Create("1", ""); err != nil {
449
+	if err := d.Create("1", "", ""); err != nil {
450 450
 		t.Fatal(err)
451 451
 	}
452 452
 
... ...
@@ -488,7 +488,7 @@ func TestChildDiffSize(t *testing.T) {
488 488
 	defer os.RemoveAll(tmp)
489 489
 	defer d.Cleanup()
490 490
 
491
-	if err := d.Create("1", ""); err != nil {
491
+	if err := d.Create("1", "", ""); err != nil {
492 492
 		t.Fatal(err)
493 493
 	}
494 494
 
... ...
@@ -524,7 +524,7 @@ func TestChildDiffSize(t *testing.T) {
524 524
 		t.Fatalf("Expected size to be %d got %d", size, diffSize)
525 525
 	}
526 526
 
527
-	if err := d.Create("2", "1"); err != nil {
527
+	if err := d.Create("2", "1", ""); err != nil {
528 528
 		t.Fatal(err)
529 529
 	}
530 530
 
... ...
@@ -543,7 +543,7 @@ func TestExists(t *testing.T) {
543 543
 	defer os.RemoveAll(tmp)
544 544
 	defer d.Cleanup()
545 545
 
546
-	if err := d.Create("1", ""); err != nil {
546
+	if err := d.Create("1", "", ""); err != nil {
547 547
 		t.Fatal(err)
548 548
 	}
549 549
 
... ...
@@ -561,7 +561,7 @@ func TestStatus(t *testing.T) {
561 561
 	defer os.RemoveAll(tmp)
562 562
 	defer d.Cleanup()
563 563
 
564
-	if err := d.Create("1", ""); err != nil {
564
+	if err := d.Create("1", "", ""); err != nil {
565 565
 		t.Fatal(err)
566 566
 	}
567 567
 
... ...
@@ -590,7 +590,7 @@ func TestApplyDiff(t *testing.T) {
590 590
 	defer os.RemoveAll(tmp)
591 591
 	defer d.Cleanup()
592 592
 
593
-	if err := d.Create("1", ""); err != nil {
593
+	if err := d.Create("1", "", ""); err != nil {
594 594
 		t.Fatal(err)
595 595
 	}
596 596
 
... ...
@@ -616,10 +616,10 @@ func TestApplyDiff(t *testing.T) {
616 616
 		t.Fatal(err)
617 617
 	}
618 618
 
619
-	if err := d.Create("2", ""); err != nil {
619
+	if err := d.Create("2", "", ""); err != nil {
620 620
 		t.Fatal(err)
621 621
 	}
622
-	if err := d.Create("3", "2"); err != nil {
622
+	if err := d.Create("3", "2", ""); err != nil {
623 623
 		t.Fatal(err)
624 624
 	}
625 625
 
... ...
@@ -647,7 +647,7 @@ func TestHardlinks(t *testing.T) {
647 647
 	origFile := "test_file"
648 648
 	linkedFile := "linked_file"
649 649
 
650
-	if err := d.Create("source-1", ""); err != nil {
650
+	if err := d.Create("source-1", "", ""); err != nil {
651 651
 		t.Fatal(err)
652 652
 	}
653 653
 
... ...
@@ -667,7 +667,7 @@ func TestHardlinks(t *testing.T) {
667 667
 		t.Fatal(err)
668 668
 	}
669 669
 
670
-	if err := d.Create("source-2", "source-1"); err != nil {
670
+	if err := d.Create("source-2", "source-1", ""); err != nil {
671 671
 		t.Fatal(err)
672 672
 	}
673 673
 
... ...
@@ -685,7 +685,7 @@ func TestHardlinks(t *testing.T) {
685 685
 		t.Fatal(err)
686 686
 	}
687 687
 
688
-	if err := d.Create("target-1", ""); err != nil {
688
+	if err := d.Create("target-1", "", ""); err != nil {
689 689
 		t.Fatal(err)
690 690
 	}
691 691
 
... ...
@@ -693,7 +693,7 @@ func TestHardlinks(t *testing.T) {
693 693
 		t.Fatal(err)
694 694
 	}
695 695
 
696
-	if err := d.Create("target-2", "target-1"); err != nil {
696
+	if err := d.Create("target-2", "target-1", ""); err != nil {
697 697
 		t.Fatal(err)
698 698
 	}
699 699
 
... ...
@@ -751,7 +751,7 @@ func testMountMoreThan42Layers(t *testing.T, mountPath string) {
751 751
 		}
752 752
 		current = hash(current)
753 753
 
754
-		if err := d.Create(current, parent); err != nil {
754
+		if err := d.Create(current, parent, ""); err != nil {
755 755
 			t.Logf("Current layer %d", i)
756 756
 			t.Error(err)
757 757
 		}
... ...
@@ -86,7 +86,7 @@ func (a *Driver) migrateContainers(pth string, setupInit func(p string, rootUID,
86 86
 				}
87 87
 
88 88
 				initID := fmt.Sprintf("%s-init", id)
89
-				if err := a.Create(initID, metadata.Image); err != nil {
89
+				if err := a.Create(initID, metadata.Image, ""); err != nil {
90 90
 					return err
91 91
 				}
92 92
 
... ...
@@ -99,7 +99,7 @@ func (a *Driver) migrateContainers(pth string, setupInit func(p string, rootUID,
99 99
 					return err
100 100
 				}
101 101
 
102
-				if err := a.Create(id, initID); err != nil {
102
+				if err := a.Create(id, initID, ""); err != nil {
103 103
 					return err
104 104
 				}
105 105
 			}
... ...
@@ -153,7 +153,7 @@ func (a *Driver) migrateImage(m *metadata, pth string, migrated map[string]bool)
153 153
 			return err
154 154
 		}
155 155
 		if !a.Exists(m.ID) {
156
-			if err := a.Create(m.ID, m.ParentID); err != nil {
156
+			if err := a.Create(m.ID, m.ParentID, ""); err != nil {
157 157
 				return err
158 158
 			}
159 159
 		}
... ...
@@ -21,6 +21,7 @@ import (
21 21
 	"github.com/docker/docker/daemon/graphdriver"
22 22
 	"github.com/docker/docker/pkg/idtools"
23 23
 	"github.com/docker/docker/pkg/mount"
24
+	"github.com/opencontainers/runc/libcontainer/label"
24 25
 )
25 26
 
26 27
 func init() {
... ...
@@ -233,7 +234,7 @@ func (d *Driver) subvolumesDirID(id string) string {
233 233
 }
234 234
 
235 235
 // Create the filesystem with given id.
236
-func (d *Driver) Create(id string, parent string) error {
236
+func (d *Driver) Create(id, parent, mountLabel string) error {
237 237
 	subvolumes := path.Join(d.home, "subvolumes")
238 238
 	rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
239 239
 	if err != nil {
... ...
@@ -255,7 +256,8 @@ func (d *Driver) Create(id string, parent string) error {
255 255
 			return err
256 256
 		}
257 257
 	}
258
-	return nil
258
+
259
+	return label.Relabel(path.Join(subvolumes, id), mountLabel, false)
259 260
 }
260 261
 
261 262
 // Remove the filesystem with given id.
... ...
@@ -133,7 +133,7 @@ func (d *Driver) Cleanup() error {
133 133
 }
134 134
 
135 135
 // Create adds a device with a given id and the parent.
136
-func (d *Driver) Create(id, parent string) error {
136
+func (d *Driver) Create(id, parent, mountLabel string) error {
137 137
 	if err := d.DeviceSet.AddDevice(id, parent); err != nil {
138 138
 		return err
139 139
 	}
... ...
@@ -48,8 +48,8 @@ type ProtoDriver interface {
48 48
 	// String returns a string representation of this driver.
49 49
 	String() string
50 50
 	// Create creates a new, empty, filesystem layer with the
51
-	// specified id and parent. Parent may be "".
52
-	Create(id, parent string) error
51
+	// specified id and parent and mountLabel. Parent and mountLabel may be "".
52
+	Create(id, parent, mountLabel string) error
53 53
 	// Remove attempts to remove the filesystem layer with this id.
54 54
 	Remove(id string) error
55 55
 	// Get returns the mountpoint for the layered filesystem referred
... ...
@@ -177,7 +177,7 @@ func DriverTestCreateEmpty(t *testing.T, drivername string) {
177 177
 	driver := GetDriver(t, drivername)
178 178
 	defer PutDriver(t)
179 179
 
180
-	if err := driver.Create("empty", ""); err != nil {
180
+	if err := driver.Create("empty", "", ""); err != nil {
181 181
 		t.Fatal(err)
182 182
 	}
183 183
 
... ...
@@ -215,7 +215,7 @@ func createBase(t *testing.T, driver graphdriver.Driver, name string) {
215 215
 	oldmask := syscall.Umask(0)
216 216
 	defer syscall.Umask(oldmask)
217 217
 
218
-	if err := driver.Create(name, ""); err != nil {
218
+	if err := driver.Create(name, "", ""); err != nil {
219 219
 		t.Fatal(err)
220 220
 	}
221 221
 
... ...
@@ -283,7 +283,7 @@ func DriverTestCreateSnap(t *testing.T, drivername string) {
283 283
 
284 284
 	createBase(t, driver, "Base")
285 285
 
286
-	if err := driver.Create("Snap", "Base"); err != nil {
286
+	if err := driver.Create("Snap", "Base", ""); err != nil {
287 287
 		t.Fatal(err)
288 288
 	}
289 289
 
... ...
@@ -230,7 +230,7 @@ func (d *Driver) Cleanup() error {
230 230
 
231 231
 // Create is used to create the upper, lower, and merge directories required for overlay fs for a given id.
232 232
 // The parent filesystem is used to configure these directories for the overlay.
233
-func (d *Driver) Create(id string, parent string) (retErr error) {
233
+func (d *Driver) Create(id, parent, mountLabel string) (retErr error) {
234 234
 	dir := d.dir(id)
235 235
 
236 236
 	rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
... ...
@@ -55,10 +55,11 @@ func (d *graphDriverProxy) String() string {
55 55
 	return d.name
56 56
 }
57 57
 
58
-func (d *graphDriverProxy) Create(id, parent string) error {
58
+func (d *graphDriverProxy) Create(id, parent, mountLabel string) error {
59 59
 	args := &graphDriverRequest{
60
-		ID:     id,
61
-		Parent: parent,
60
+		ID:         id,
61
+		Parent:     parent,
62
+		MountLabel: mountLabel,
62 63
 	}
63 64
 	var ret graphDriverResponse
64 65
 	if err := d.client.Call("GraphDriver.Create", args, &ret); err != nil {
... ...
@@ -66,7 +66,7 @@ func (d *Driver) Cleanup() error {
66 66
 }
67 67
 
68 68
 // Create prepares the filesystem for the VFS driver and copies the directory for the given id under the parent.
69
-func (d *Driver) Create(id, parent string) error {
69
+func (d *Driver) Create(id, parent, mountLabel string) error {
70 70
 	dir := d.dir(id)
71 71
 	rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
72 72
 	if err != nil {
... ...
@@ -129,7 +129,7 @@ func (d *Driver) Exists(id string) bool {
129 129
 }
130 130
 
131 131
 // Create creates a new layer with the given id.
132
-func (d *Driver) Create(id, parent string) error {
132
+func (d *Driver) Create(id, parent, mountLabel string) error {
133 133
 	rPId, err := d.resolveID(parent)
134 134
 	if err != nil {
135 135
 		return err
... ...
@@ -241,7 +241,7 @@ func (d *Driver) mountPath(id string) string {
241 241
 }
242 242
 
243 243
 // Create prepares the dataset and filesystem for the ZFS driver for the given id under the parent.
244
-func (d *Driver) Create(id string, parent string) error {
244
+func (d *Driver) Create(id string, parent string, mountLabel string) error {
245 245
 	err := d.create(id, parent)
246 246
 	if err == nil {
247 247
 		return nil
... ...
@@ -29,6 +29,12 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *runconfig.HostConf
29 29
 		// This is kept for backward compatibility - hostconfig should be passed when
30 30
 		// creating a container, not during start.
31 31
 		if hostConfig != nil {
32
+			container.Lock()
33
+			if err := parseSecurityOpt(container, hostConfig); err != nil {
34
+				container.Unlock()
35
+				return err
36
+			}
37
+			container.Unlock()
32 38
 			if err := daemon.setHostConfig(container, hostConfig); err != nil {
33 39
 				return err
34 40
 			}
... ...
@@ -359,7 +359,7 @@ func (graph *Graph) register(im image.Descriptor, layerData io.Reader) (err erro
359 359
 }
360 360
 
361 361
 func createRootFilesystemInDriver(graph *Graph, id, parent string) error {
362
-	if err := graph.driver.Create(id, parent); err != nil {
362
+	if err := graph.driver.Create(id, parent, ""); err != nil {
363 363
 		return fmt.Errorf("Driver %s failed to create image rootfs %s: %s", graph.driver, id, err)
364 364
 	}
365 365
 	return nil
... ...
@@ -122,7 +122,7 @@ func (s *DockerExternalGraphdriverSuite) SetUpSuite(c *check.C) {
122 122
 		if err := decReq(r.Body, &req, w); err != nil {
123 123
 			return
124 124
 		}
125
-		if err := driver.Create(req.ID, req.Parent); err != nil {
125
+		if err := driver.Create(req.ID, req.Parent, ""); err != nil {
126 126
 			respond(w, err)
127 127
 			return
128 128
 		}
... ...
@@ -191,7 +191,7 @@ unix://[/path/to/socket] to use.
191 191
   Force the Docker runtime to use a specific storage driver.
192 192
 
193 193
 **--selinux-enabled**=*true*|*false*
194
-  Enable selinux support. Default is false. SELinux does not presently support the BTRFS storage driver.
194
+  Enable selinux support. Default is false. SELinux does not presently support the overlay storage driver.
195 195
 
196 196
 **--storage-opt**=[]
197 197
   Set storage driver options. See STORAGE DRIVER OPTIONS.