Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mount: support checking multiple kinds of block device driver #4743

Merged
merged 1 commit into from Dec 5, 2023

Conversation

yuchen0cc
Copy link
Contributor

Device mapper is the only supported block device driver so far, which seems limiting. Kata Containers can work well with other block devices. It is necessary to enhance supporting of multiple kinds of host block device.

Fixes #4714

Signed-off-by: yuchen.cc yuchen.cc@alibaba-inc.com

@katacontainersbot katacontainersbot added the size/small Small and simple task label Jul 26, 2022
@yuchen0cc
Copy link
Contributor Author

Please tell me the porting labels to be applied.

@katacontainersbot
Copy link
Contributor

Can one of the admins verify this patch?

Copy link
Member

@bergwolf bergwolf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A more general question: the DM device check is a workaround for the device mapper snapshotter. Please explain a bit why we need to check for the extra block device types and how they are supposed to work with Kata Containers. Thanks!

@@ -208,7 +208,7 @@ func getDeviceForPath(path string) (device, error) {

var blockFormatTemplate = "/sys/dev/block/%d:%d/dm"

var checkStorageDriver = isDeviceMapper
var checkStorageDriver = checkBlockDevice
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isDeviceMapper is left over but it's a piece of dead code now? And the new code is not unit-tested as the code pieces.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for adding unit tests.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for removing the isDeviceMapper code if not used

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link

@shuaichang shuaichang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for making the change, very useful to extend block device support outside of device mapper!

@@ -208,7 +208,7 @@ func getDeviceForPath(path string) (device, error) {

var blockFormatTemplate = "/sys/dev/block/%d:%d/dm"

var checkStorageDriver = isDeviceMapper
var checkStorageDriver = checkBlockDevice

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for adding unit tests.

@@ -226,6 +226,40 @@ func isDeviceMapper(major, minor int) (bool, error) {
return false, err
}

var blockFormatTemplates = map[string]string{

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: blockFormatTemplates -> blockFormatFmts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blockFormatTemplates is consist with old code.

}

func checkBlockDevice(major, minor int) (bool, error) {
var lastErr error = nil

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

= nil seems to be unnecessary

for dev, template := range blockFormatTemplates {
isBD, err := isBlockDevice(major, minor, template)
if isBD {
mountLogger().Infof("Found storage driver for %s", dev)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This log seems to be a little off from the context, can we log "device % is identified as a block device"?

_, err := os.Stat(sysPath)
if err == nil {
return true, nil
} else if os.IsNotExist(err) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can remove the else if, or to add the last return into an else block for consistency

if err == nil {
    return true, nil
}

if os.IsNotExist(err) {
    return false, nil
}

return false, err

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -208,7 +208,7 @@ func getDeviceForPath(path string) (device, error) {

var blockFormatTemplate = "/sys/dev/block/%d:%d/dm"

var checkStorageDriver = isDeviceMapper
var checkStorageDriver = checkBlockDevice

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for removing the isDeviceMapper code if not used

mountLogger().Infof("Found storage driver for %s", dev)
return isBD, err
} else if err != nil {
lastErr = err

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make this logic easier to understand like the following? I think if any error occurred while checking can just throw the error without continuing.

isBD, err := isBlockDevice(major, minor, template)
if err != nil {
    return 
}

@yuchen0cc
Copy link
Contributor Author

@bergwolf Thanks for commenting!
Kata Containers has already supported using block device as container's rootfs, and it is the only way for firecracker.
Device mapper is the only supported block device driver so far, which seems limiting. Actually, Kata Containers can work well with raw image on loop device or overlaybd on tcmu device. It is necessary to enhance supporting of multiple kinds of host block device driver.

I will add unit test and remove unused code.

@yuchen0cc
Copy link
Contributor Author

What does "add-pr-size-label" failed mean ?


// fake the block device format
blockFormatTemplate = "/sys/dev/char/%d:%d"
isDM, err = isDeviceMapper(major, minor)
blockFormatTemplates = map[string]string{

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better to reset blockFormatTemplates so in case other case will not be impacted, I think the old code probably missed this part

	blockFormatTemplatesOld := blockFormatTemplates
	defer func() {
		blockFormatTemplates = blockFormatTemplatesOld
	}()
	blockFormatTemplates = map[string]string{
		"/dev/tty": "/sys/dev/char/%d:%d",
	}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a good way, I have done so.

for dev, template := range blockFormatTemplates {
isBD, err := isBlockDevice(major, minor, template)
if err != nil {
return false, err

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add UTs to cover all the branches for the newly added code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The unchecked branch is err != nil which only happens when isBlockDevice return error. That happens when os.Stat fails and not because of os.IsNotExist.
I really don't know when it happens. Do you have any idea?

Copy link
Contributor

@sazzy4o sazzy4o Nov 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the easiest way to accomplish this here is to use a path with an invalid character (the null character \000 will work for both unix and window systems):

fmt.Println("Example: Invalid character")
_, err := os.Stat("\000path")
fmt.Println(err)

You can override the blockFormatTemplates like you did the tests below to get a path with \000 in it

(Permissions errors should also work, but might be a little hard to setup tests for)

Also, if you need help getting this PR to the finish line, please let me know

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sazzy4o I have supplemented the test as you suggested.
It's really grateful that you can help finishing this PR.

@katacontainersbot katacontainersbot added size/medium Average sized task and removed size/small Small and simple task labels Apr 20, 2023
@sazzy4o
Copy link
Contributor

sazzy4o commented Nov 21, 2023

@shuaichang Could you please have another look at reviewing this PR?

Copy link

@shuaichang shuaichang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@sazzy4o
Copy link
Contributor

sazzy4o commented Nov 21, 2023

@yuchen0cc Could you please merge kata-containers:main into your branch, I think one of the PR checks is failing because the branch is not up to date?

@yuchen0cc
Copy link
Contributor Author

yuchen0cc commented Nov 22, 2023

@yuchen0cc Could you please merge kata-containers:main into your branch, I think one of the PR checks is failing because the branch is not up to date?

OK, I've rebase it by mainstream.

@sazzy4o
Copy link
Contributor

sazzy4o commented Nov 22, 2023

@bergwolf Could you please review this PR?

@sazzy4o
Copy link
Contributor

sazzy4o commented Nov 26, 2023

@yuchen0cc It looks like one of the checks is failing because a749dd1 does not have a commit message body

I think updating it to something like this should work:

mount_test: supplement test for checking block device

Adds test for handling os.Stat error

Signed-off-by: yuchen.cc <yuchen.cc@alibaba-inc.com>

See here for more info on expected commit message format

I hope this is the last change. If you want me to take over changes to this PR, please let me know (I just need permission to push to your fork)

@yuchen0cc
Copy link
Contributor Author

@sazzy4o sorry to forget this checking, I've fixed it.

Copy link
Member

@bergwolf bergwolf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks useful to enable overlaybd for Kata. Could you add a howto document in the docs/how-to/ directory?

After discussing with @sazzy4o, it is completely transparent, we do not need a specific overlaybd howto in kata.

//Check if /sys/dev/block/${major}-${minor}/dm exists
sysPath := fmt.Sprintf(blockFormatTemplate, major, minor)
func isBlockDevice(major, minor int, formatTemplate string) (bool, error) {
sysPath := fmt.Sprintf(formatTemplate, major, minor)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not seem to work for nvme devices. Why not just check for /sys/dev/block/<major:minor>/ and forget about the specific block device types?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have actually tested the above 3 block types with kata, and I'm not sure kata is compatible with all block types.
Just to be cautious, I make a minimal supportation, and allow for extensions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All block devices are equal in terms of virtio-block backend. So it doesn't matter where it comes from.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, it seems reasonable.

@katacontainersbot katacontainersbot added size/small Small and simple task and removed size/medium Average sized task labels Nov 30, 2023
@yuchen0cc
Copy link
Contributor Author

As suggested by @bergwolf , I think there is no longer need to check multiple templates (using map and loop).
So I squash the previous 2 commit and make it a minor change.
@shuaichang @sazzy4o @bergwolf Could you please take a look at this.

Copy link
Member

@bergwolf bergwolf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm!

@yuchen0cc
Copy link
Contributor Author

yuchen0cc commented Dec 1, 2023

TestIsDeviceMapper has been moved from mount_test.go to mount_linux_test
I need to move correspondingly.

@bergwolf
Copy link
Member

bergwolf commented Dec 1, 2023

Please test the code locally before sending it for review.

# github.com/kata-containers/kata-containers/src/runtime/virtcontainers [github.com/kata-containers/kata-containers/src/runtime/virtcontainers.test]
virtcontainers/mount_linux_test.go:315:15: undefined: isDeviceMapper
virtcontainers/mount_linux_test.go:[32](https://github.com/kata-containers/kata-containers/actions/runs/7047880519/job/19205798649?pr=4743#step:9:33)1:14: undefined: isDeviceMapper

Device mapper is the only supported block device driver so far,
which seems limiting. Kata Containers can work well with other
block devices. It is necessary to enhance supporting of multiple
kinds of host block device.

Fixes kata-containers#4714

Signed-off-by: yuchen.cc <yuchen.cc@alibaba-inc.com>
@sazzy4o
Copy link
Contributor

sazzy4o commented Dec 1, 2023

I think that code looks good, but I'll try running locally (I think I should have some time to test locally tomorrow)

@sazzy4o
Copy link
Contributor

sazzy4o commented Dec 3, 2023

Tested locally with overlaybd and it works as expected:

$ sudo nerdctl run --cgroup-manager=cgroupfs --runtime io.containerd.run.kata.v2 --snapshotter=overlaybd --rm -it registry.hub.docker.com/overlaybd/redis:6.2.1_obd /bin/sh
# df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda         63G  107M   60G   1% /
tmpfs            64M     0   64M   0% /dev
none            322G  179G  127G  59% /data
shm             996M     0  996M   0% /dev/shm
tmpfs           996M     0  996M   0% /sys/fs/cgroup
kataShared      322G  179G  127G  59% /etc/hosts
# 

Notes:

  • Tested with cloud-hypervisor
  • overlaybd installed via instructions here
  • Important: sandbox_cgroup_only=true must be set in your configuration.toml

Copy link
Contributor

@sazzy4o sazzy4o left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good and works when testing locally

@jepio
Copy link
Member

jepio commented Dec 5, 2023

/test-arm
/test-s390x

Copy link
Member

@jepio jepio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks reasonable

@jepio jepio merged commit e2c6b8a into kata-containers:main Dec 5, 2023
158 of 164 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ok-to-test size/small Small and simple task
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Enhance supporting multiple kinds of host block device
8 participants