-
Notifications
You must be signed in to change notification settings - Fork 18.7k
Add vfs quota support #35231
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
Add vfs quota support #35231
Conversation
8a32b5e
to
5b2a9d2
Compare
what motivates you to use vfs? |
@AkihiroSuda "It just works" (mostly). My containers run from 2 minutes to 2 months. The median runtime of my containers is 4-5 minutes. Setting up VFS, with the improvements that come from #34670 has an unoptimized mean time of ~45s for copying ubuntu:latest. We can optimize that down to <10s. If I can optimize these times, it prevents any potential hiccups from occurring at runtime, versus startup time. Never having to worry about overlayfs, or such, there's some appeal there. |
@dmcgowan We discussed this change earlier. |
@@ -12,6 +12,8 @@ import ( | |||
"testing" | |||
"unsafe" | |||
|
|||
"github.com/docker/docker/daemon/graphdriver/quota" | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can you remove this blank line?
/cc @kolyshkin as well |
5b2a9d2
to
d348809
Compare
Rebased. |
b37e83e
to
e85698e
Compare
This should be ready to go in. |
driver := GetDriver(t, drivername) | ||
defer PutDriver(t) | ||
|
||
createBase(t, driver, "Base") | ||
createOpts := &graphdriver.CreateOpts{} | ||
createOpts.StorageOpt = make(map[string]string, 1) | ||
createOpts.StorageOpt["size"] = "50M" | ||
if err := driver.Create("zfsTest", "Base", createOpts); err != nil { | ||
if err := driver.CreateReadWrite("zfsTest", "Base", createOpts); err == quota.ErrQuotaNotSupported && !required { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps it makes sense to rename "zfsTest"
to drivername + "Test"
as it's no longer zfs-specific. Or just "quotaTest"
...
} | ||
|
||
// Try to write a file bigger than quota, and ensure it does not work | ||
if pathError, ok := err.(*os.PathError); ok && pathError.Err != unix.EDQUOT && pathError.Err != unix.ENOSPC { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Looks like you're missing a line here? Something like
+ err = writeRandomFile(path.Join(mountPath.Path(), "file"), quota*2)
- Since you have already exhausted half the quota by doing a write above, you might either go with a smaller value than
quota*2
, or remove the file written above.
|
||
// Try to write a file bigger than quota, and ensure it does not work | ||
if pathError, ok := err.(*os.PathError); ok && pathError.Err != unix.EDQUOT && pathError.Err != unix.ENOSPC { | ||
t.Fatalf("expect write() to fail with %v or %v, got %v", unix.EDQUOT, unix.ENOSPC, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps you want to print pathError.Err
here, not err
, as this is what you use in comparisons?
daemon/graphdriver/vfs/driver.go
Outdated
home string | ||
idMappings *idtools.IDMappings | ||
driverQuota | ||
quotaSupported bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this can be done in a simple manner, without an extra bool
field. The idea is to add isQuotaSupported()
method. In quota_linux.go
, it is just return driver.quotaCtl != nil
, in quota_unsupported.go
, return false straight away. To my mind, it will be cleaner/simpler.
e85698e
to
1dc0690
Compare
Updated based on review. |
} | ||
|
||
func (d *Driver) setupQuota(dir string, size uint64) error { | ||
panic("Platform does not support quota; this should never be called") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Panic seems a little harsh here. Can we just return a not supported error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should never be called. If this is called, it means something has gone wrong, or the code was changed in an unexpected way.
1dc0690
to
2cbdc8c
Compare
ping @cpuguy83 |
} | ||
defer os.Remove(path.Join(mountPath.Path(), "smallfile")) | ||
|
||
// Try to write a file bigger than quota, given that we've already written a file larger than quota, and ensure it does not work |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this comment isn't right, we have written a file of half quota at this point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
2cbdc8c
to
ca5e654
Compare
daemon/graphdriver/quota/errors.go
Outdated
import "errors" | ||
|
||
// ErrQuotaNotSupported indicates if were found the FS didn't have projects quotas available | ||
var ErrQuotaNotSupported = errors.New("Filesystem does not support, or has not enabled quotas") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make sure this error implements one of api/errdefs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which one do you think it should be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ErrNotImplemented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or ErrUnavailable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NotImplemented sounds good.
ca5e654
to
1fa28b0
Compare
1fa28b0
to
5eb1c11
Compare
This patch adds the capability for the VFS graphdriver to use XFS project quotas. It reuses the existing quota management code that was created by overlay2 on XFS. It doesn't rely on a filesystem whitelist, but instead the quota-capability detection code. Signed-off-by: Sargun Dhillon <sargun@sargun.me>
5eb1c11
to
7a1618c
Compare
@cpuguy83 Anything else? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
- What I did
Added project quota support to the VFS graphdriver, and tests to ensure they work.
It relies on #35177, which adds the quota detection mechanism, and a form error to determine whether to short-circuit quota-related code (or not).
It addresses this issue: #34702
- How I did it
I reused the project quota code that came from overlay2. On initialization time, the VFS driver (on Linux) detects if quota is supported. If quota is supported, then it enables the MaxSize option, so new containers can be created with an assigned project quota.
- How to verify it
There are tests as part of the changeset. If you run the tests when your
TMPDIR
environment variable points to an XFS mount mounted withprjquota
option, the quota check will run automatically, otherwise, it'll be skipped.- Description for the changelog
Add project quota support to VFS graphdriver