Skip to content

Commit

Permalink
Merge pull request #1444 from saschagrunert/release-1.32-recreate-bac…
Browse files Browse the repository at this point in the history
…kingFsBlockDev

[release-1.32] Recreate missing backingFsBlockDev on setting xfs project quota
  • Loading branch information
rhatdan authored Dec 5, 2022
2 parents eb59ab4 + e7cd856 commit faa8a9f
Showing 1 changed file with 43 additions and 17 deletions.
60 changes: 43 additions & 17 deletions drivers/quota/projectquota.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//go:build linux && !exclude_disk_quota && cgo
// +build linux,!exclude_disk_quota,cgo

//
Expand Down Expand Up @@ -50,10 +51,12 @@ struct fsxattr {
*/
import "C"
import (
"errors"
"fmt"
"io/ioutil"
"path"
"path/filepath"
"syscall"
"unsafe"

"github.com/containers/storage/pkg/directory"
Expand All @@ -72,6 +75,7 @@ type Control struct {
backingFsBlockDev string
nextProjectID uint32
quotas map[string]uint32
basePath string
}

// NewControl - initialize project quota support.
Expand Down Expand Up @@ -121,20 +125,22 @@ func NewControl(basePath string) (*Control, error) {
quota := Quota{
Size: 0,
}
if err := setProjectQuota(backingFsBlockDev, minProjectID, quota); err != nil {
return nil, err
}

q := Control{
backingFsBlockDev: backingFsBlockDev,
nextProjectID: minProjectID + 1,
quotas: make(map[string]uint32),
basePath: basePath,
}

if err := q.setProjectQuota(minProjectID, quota); err != nil {
return nil, err
}

//
// get first project id to be used for next container
//
err = q.findNextProjectID(basePath)
err = q.findNextProjectID()
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -167,11 +173,11 @@ func (q *Control) SetQuota(targetPath string, quota Quota) error {
// set the quota limit for the container's project id
//
logrus.Debugf("SetQuota(%s, %d): projectID=%d", targetPath, quota.Size, projectID)
return setProjectQuota(q.backingFsBlockDev, projectID, quota)
return q.setProjectQuota(projectID, quota)
}

// setProjectQuota - set the quota for project id on xfs block device
func setProjectQuota(backingFsBlockDev string, projectID uint32, quota Quota) error {
func (q *Control) setProjectQuota(projectID uint32, quota Quota) error {
var d C.fs_disk_quota_t
d.d_version = C.FS_DQUOT_VERSION
d.d_id = C.__u32(projectID)
Expand All @@ -181,15 +187,35 @@ func setProjectQuota(backingFsBlockDev string, projectID uint32, quota Quota) er
d.d_blk_hardlimit = C.__u64(quota.Size / 512)
d.d_blk_softlimit = d.d_blk_hardlimit

var cs = C.CString(backingFsBlockDev)
var cs = C.CString(q.backingFsBlockDev)
defer C.free(unsafe.Pointer(cs))

_, _, errno := unix.Syscall6(unix.SYS_QUOTACTL, C.Q_XSETPQLIM,
uintptr(unsafe.Pointer(cs)), uintptr(d.d_id),
uintptr(unsafe.Pointer(&d)), 0, 0)
if errno != 0 {
return fmt.Errorf("Failed to set quota limit for projid %d on %s: %v",
projectID, backingFsBlockDev, errno.Error())
runQuotactl := func() syscall.Errno {
_, _, errno := unix.Syscall6(unix.SYS_QUOTACTL, C.Q_XSETPQLIM,
uintptr(unsafe.Pointer(cs)), uintptr(d.d_id),
uintptr(unsafe.Pointer(&d)), 0, 0)
return errno
}

errno := runQuotactl()

// If the backingFsBlockDev does not exist any more then try to recreate it.
if errors.Is(errno, unix.ENOENT) {
if _, err := makeBackingFsDev(q.basePath); err != nil {
return fmt.Errorf(
"failed to recreate missing backingFsBlockDev %s for projid %d: %w",
q.backingFsBlockDev, projectID, err,
)
}

if errno := runQuotactl(); errno != 0 {
return fmt.Errorf("failed to set quota limit for projid %d on %s after backingFsBlockDev recreation: %w",
projectID, q.backingFsBlockDev, errno)
}

} else if errno != 0 {
return fmt.Errorf("failed to set quota limit for projid %d on %s: %w",
projectID, q.backingFsBlockDev, errno)
}

return nil
Expand Down Expand Up @@ -287,16 +313,16 @@ func setProjectID(targetPath string, projectID uint32) error {

// findNextProjectID - find the next project id to be used for containers
// by scanning driver home directory to find used project ids
func (q *Control) findNextProjectID(home string) error {
files, err := ioutil.ReadDir(home)
func (q *Control) findNextProjectID() error {
files, err := ioutil.ReadDir(q.basePath)
if err != nil {
return fmt.Errorf("read directory failed : %s", home)
return fmt.Errorf("read directory failed : %s", q.basePath)
}
for _, file := range files {
if !file.IsDir() {
continue
}
path := filepath.Join(home, file.Name())
path := filepath.Join(q.basePath, file.Name())
projid, err := getProjectID(path)
if err != nil {
return err
Expand Down

0 comments on commit faa8a9f

Please sign in to comment.